Skip to content

Conversation

terabytesoftw
Copy link
Member

@terabytesoftw terabytesoftw commented Sep 5, 2025

Summary by CodeRabbit

  • New Features

    • Added a complete Docker-based setup (dev, prod, full/testing) with Apache, PHP configs, Xdebug, healthcheck, and optional MySQL, PostgreSQL, Redis, MongoDB, MSSQL, and Oracle services.
    • Provided docker-compose orchestration and environment-specific PHP/Apache configurations.
  • Documentation

    • Introduced a Code of Conduct.
    • Added issue and pull request templates.
  • Chores

    • Added editor and Git attributes configuration; expanded .gitignore.
    • Enabled automated dependency updates via Dependabot.
    • Added funding configuration.
    • Updated license header.

@terabytesoftw terabytesoftw added the enhancement New feature or request label Sep 5, 2025
Copy link

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds repository configs (.editorconfig, .gitattributes, .gitignore, LICENSE) and GitHub meta (.github/*). Introduces multi-stage Apache/PHP Dockerfile and docker-compose with dev/prod/full stacks plus DB services. Adds Apache and PHP configs, Xdebug settings, and shell scripts for entrypoint, MSSQL, and Oracle driver installation.

Changes

Cohort / File(s) Summary
Repository configuration
/.editorconfig, /.gitattributes, /.gitignore, /LICENSE
Adds editor, Git attributes, ignore rules; updates license header.
GitHub repository meta
.github/CODE_OF_CONDUCT.md, .github/FUNDING.yml, .github/ISSUE_TEMPLATE.md, .github/PULL_REQUEST_TEMPLATE.md, .github/dependabot.yml
Adds community docs, funding, issue/PR templates, and Dependabot config.
Docker orchestration
/docker-compose.yml, /Dockerfile.apache
Introduces multi-stage build (dev/prod/full), optional Oracle/MSSQL support, and multi-service compose stack (app + MySQL/Postgres/Redis/MongoDB/MSSQL/Oracle).
Apache configuration
docker/configs/apache/apache2.conf, docker/configs/apache/vhost.conf
Adds base Apache server config and Yii2 vhost with rewrites, caching, compression, and headers.
PHP configuration
docker/configs/php/dev.ini, docker/configs/php/full.ini, docker/configs/php/prod.ini, docker/configs/php/xdebug.ini
Adds environment-specific PHP INI files and Xdebug settings.
Docker scripts
docker/scripts/entrypoint.sh, docker/scripts/install-mssql.sh, docker/scripts/install-oracle.sh
Adds entrypoint for runtime setup/migrations/healthcheck and installers for MSSQL and Oracle clients/extensions.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant D as Docker Engine
  participant DF as Dockerfile.apache
  participant MS as install-mssql.sh
  participant OR as install-oracle.sh
  Dev->>D: docker build --build-arg BUILD_TYPE=dev|prod|full
  D->>DF: Execute multi-stage build
  activate DF
  DF->>DF: base → builder → asset-builder
  alt BUILD_TYPE == dev|full
    DF->>DF: dev stage (tools, xdebug)
  end
  alt BUILD_TYPE == full
    DF->>MS: Optional MSSQL drivers/extensions
    DF->>OR: Optional Oracle client/extensions
  end
  alt BUILD_TYPE == prod
    DF->>DF: prod stage (prod extensions)
  end
  DF->>DF: final stage FROM ${BUILD_TYPE}
  deactivate DF
  D-->>Dev: Emits final image
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant C as Container (Entrypoint)
  participant A as Apache/PHP
  participant APP as Yii2 App
  participant DB as Databases (MySQL/PG/MSSQL/Oracle/Mongo/Redis)

  U->>C: docker compose up
  activate C
  C->>C: Configure Apache/PHP, Xdebug, memory
  C->>DB: wait_for_service(...) (conditional per env)
  C->>APP: composer install (if needed)
  alt RUN_MIGRATIONS == true and not test
    C->>APP: yii migrate --interactive=0
  end
  C->>APP: Optional /web/health.php generation
  C->>A: exec apache2 -DFOREGROUND
  deactivate C

  U->>A: HTTP requests (/)
  A->>APP: Route to index.php (rewrites)
  APP-->>DB: Query/Cache (as configured)
  A-->>U: Response

  U->>A: GET /health
  A->>APP: health.php (if enabled)
  APP-->>U: JSON status
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Poem

I nibbled configs, crisp and light,
Docked a fleet for day and night.
With apache burrows, PHP breeze,
Databases hum with ease.
Healthchecks hop, migrations run—
Carrots cached, deploys are done. 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e8ddd82 and ecf6677.

📒 Files selected for processing (2)
  • Dockerfile.apache (1 hunks)
  • docker/scripts/entrypoint.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • docker/scripts/entrypoint.sh
  • Dockerfile.apache
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feture-1

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

…ct, Funding, Issue and Pull Request templates, and Dependabot settings.
Copy link

@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.

Actionable comments posted: 46

🧹 Nitpick comments (87)
.github/FUNDING.yml (1)

4-4: Remove stray trailing content.

There appears to be an extra line containing just “4”. Clean it up to avoid YAML parsing noise.

-4
+
.github/ISSUE_TEMPLATE.md (2)

10-14: Tighten placeholders and make version guidance clearer.

Use a concrete semver placeholder and nudge reporters to paste exact versions.

-| Version          | 1.0.?
-| PHP version      | 
+| App/Template version | 1.x (exact: e.g., 1.2.3)
+| PHP version          | 8.x (exact: e.g., 8.3.9)

1-9: Consider migrating to Issue Forms for structured input.

GitHub Issue Forms (YAML) give required fields, dropdowns, and validation; fewer back-and-forths.

I can draft bug_report.yml and feature_request.yml under .github/ISSUE_TEMPLATE/ if you want.

docker/configs/php/xdebug.ini (1)

4-8: Improve cross-OS connectivity (Linux) and debuggability.

host.docker.internal may not resolve on Linux. Enabling client discovery is a safe default for dev; also add an optional log path for faster troubleshooting.

 xdebug.client_host = host.docker.internal
 xdebug.client_port = 9003
 xdebug.start_with_request = yes
 xdebug.idekey = PHPSTORM
-xdebug.discover_client_host = 0
+xdebug.discover_client_host = 1
 xdebug.log_level = 0
+; Uncomment for troubleshooting when log_level > 0
+; xdebug.log = /tmp/xdebug.log

Please verify this still aligns with any overrides done in your entrypoint or env vars.

.github/PULL_REQUEST_TEMPLATE.md (2)

1-6: Use actual checkboxes and auto-close keywords.

Checkboxes render better with [ ]/[x], and using “Fixes #ID” auto-closes issues on merge.

-| Q             | A
-| ------------- | ---
-| Is bugfix?    | ✔️/❌
-| New feature?  | ✔️/❌
-| Breaks BC?    | ✔️/❌
-| Fixed issues  | <!-- comma-separated list of tickets # fixed by the PR, if any -->
+| Q             | A
+| ------------- | ---
+| Is bugfix?    | [ ] Yes  [ ] No
+| New feature?  | [ ] Yes  [ ] No
+| Breaks BC?    | [ ] Yes  [ ] No
+| Fixes         | <!-- e.g. Fixes #123, Closes #456 -->

1-6: Add “How to test” and “Breaking changes” sections.

Helps reviewers and downstream users when BC breaks are marked “Yes”.

 | Breaks BC?    | [ ] Yes  [ ] No
 | Fixes         | <!-- e.g. Fixes #123, Closes #456 -->
+
+## How to test
+<!-- Steps, commands, sample env vars -->
+
+## Breaking changes
+<!-- Migration notes, config changes, deprecations -->
.github/dependabot.yml (2)

4-8: Reduce noise and add metadata to updates.

Optional tweaks: limit concurrent PRs and add labels to aid triage; schedule weekly to avoid churn.

   - package-ecosystem: "github-actions"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
+    open-pull-requests-limit: 5
+    labels: ["dependencies"]
+    target-branch: "main"

10-14: Composer updates: same quality-of-life improvements.

Keep increase-if-necessary, add labeling/limits/explicit target branch.

   - package-ecosystem: "composer"
     directory: "/"
     schedule:
-      interval: "daily"
+      interval: "weekly"
     versioning-strategy: increase-if-necessary
+    open-pull-requests-limit: 5
+    labels: ["dependencies", "composer"]
+    target-branch: "main"
.editorconfig (2)

20-21: Add YAML extension alias (.yaml) to keep settings consistent.

Many repos use both .yml and .yaml. Include both to avoid drift.

-[*.yml]
-indent_size = 2
+[*.{yml,yaml}]
+indent_size = 2

13-16: JetBrains-specific keys are fine; consider scoping/commenting them.

The ij_php_* options are IDE-specific. Add a short comment above to clarify for non-IntelliJ users.

LICENSE.md (1)

3-3: Confirm copyright year range.

If the project is active through 2025, consider “2008–2025” to reflect continuity.

.gitignore (2)

11-13: Optional: ignore common local files.

Add .DS_Store and .vscode to reduce noise.

 # phpstorm project files
 .idea
+.vscode
+.DS_Store

20-21: Minor wording nit: comment capitalization.

Match style of other comments.

-#yii3 config packages
+# Yii3 config packages
.github/CODE_OF_CONDUCT.md (3)

5-6: Tighten wording for clarity.

Small grammar tweaks.

-As contributors and maintainers of this project, and in order to keep community open and welcoming, we ask to
-respect all community members.
+As contributors and maintainers of this project, to keep the community open and welcoming, we ask that you
+respect all community members.

39-41: Polish example phrasing.

Improves readability.

- address, posting via an official social media account, within project GitHub, official forum or acting as an appointed
+ address, posting via an official social media account, on the project’s GitHub or official forum, or acting as an appointed

45-46: Add a concrete reporting channel.

Specify an email or URL for incident reports (e.g., abuse@example.org or a GitHub Security Advisory contact).

Share the preferred contact and I can amend the section.

docker/requirements/assets/css/app.css (3)

31-45: Consider 100dvh for mobile browser chrome.

100vh can be problematic on iOS; 100dvh adapts to dynamic viewport.

-    height: 100vh;
+    height: 100dvh;

476-496: Respect prefers-reduced-motion.

Reduce animations for accessibility.

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .status-indicator,
  .requirement-item,
  .nav.flex-column .nav-link:hover {
    animation: none !important;
    transition: none !important;
    transform: none !important;
  }
}

14-25: Add a global border-box reset to avoid sizing surprises.

Helps keep layout predictable with paddings/borders.

*, *::before, *::after { box-sizing: border-box; }
.gitattributes (3)

14-14: Ensure .bat scripts use CRLF to avoid breakage on Windows

Global eol=lf forces LF on checkout; override .bat to CRLF.

Apply:

-*.bat  text
+*.bat  text eol=crlf

12-17: Cover common text config extensions

Add yaml/conf/ini/env to keep consistent EOL/filters.

 *.xml  text
 *.json text
-*.bat  text
+*.bat  text eol=crlf
 *.sql  text
 *.yml  text
+*.yaml text
+*.conf text
+*.ini  text
+*.env  text

18-23: Broaden binary pinning for assets

Prevents diff/filters from mangling binaries.

 *.png  binary
 *.jpg  binary
+*.jpeg binary
 *.gif  binary
 *.ttf  binary
+*.woff  binary
+*.woff2 binary
+*.eot   binary
+*.ico   binary
+*.webp  binary
+*.pdf   binary
docker/configs/apache/vhost.conf (6)

7-11: Harden directory scope and disable .htaccess parsing

Use AllowOverride None (perf/security) and add DirectoryIndex.

-    <Directory /var/www/app/web>
-        Options -Indexes +FollowSymLinks
-        AllowOverride All
+    <Directory /var/www/app/web>
+        Options -Indexes -MultiViews +FollowSymLinks
+        AllowOverride None
         Require all granted
+        DirectoryIndex index.php

15-19: Simplify trailing-slash redirect to avoid REQUEST_URI coupling

Cleaner and avoids edge-cases in Directory context.

-        # Redirect trailing slashes if not a directory
-        RewriteCond %{REQUEST_FILENAME} !-d
-        RewriteCond %{REQUEST_URI} (.+)/$
-        RewriteRule ^ %1 [L,R=301]
+        # Redirect trailing slashes if not a directory
+        RewriteCond %{REQUEST_FILENAME} !-d
+        RewriteRule ^(.+?)/$ $1 [R=301,L]

43-49: Prefer Brotli when available; keep Deflate as fallback

Brotli provides better compression for text assets.

     # Compression
     <IfModule mod_deflate.c>
         AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
         AddOutputFilterByType DEFLATE text/javascript application/javascript application/json
         AddOutputFilterByType DEFLATE application/xml application/xhtml+xml application/rss+xml
     </IfModule>
+
+    <IfModule mod_brotli.c>
+        BrotliCompressionQuality 5
+        AddOutputFilterByType BROTLI_COMPRESS text/html text/plain text/xml text/css \
+          application/javascript application/json application/xml image/svg+xml
+    </IfModule>

26-41: Deny sensitive files inside DocumentRoot instead of out-of-root dirs

Apache won’t serve /runtime, /vendor, /tests, /config outside the docroot. Deny common secrets within /web instead.

     # Protect sensitive directories
-    <Directory /var/www/app/runtime>
-        Require all denied
-    </Directory>
-    
-    <Directory /var/www/app/vendor>
-        Require all denied
-    </Directory>
-    
-    <Directory /var/www/app/tests>
-        Require all denied
-    </Directory>
-    
-    <Directory /var/www/app/config>
-        Require all denied
-    </Directory>
+    <FilesMatch "(\.env|\.env\.[A-Za-z0-9_-]+|composer\.(json|lock)|package(-lock)?\.json|yarn\.lock)">
+        Require all denied
+    </FilesMatch>

Please confirm your app indeed serves only from /var/www/app/web; if you expose aliases/symlinks into parent paths, keep explicit denies.


68-73: Replace deprecated X-XSS-Protection; add CSP and hide X-Powered-By

Modern hardening without breaking defaults (tune CSP per app).

     # Security headers
     <IfModule mod_headers.c>
         Header always set X-Frame-Options "SAMEORIGIN"
         Header always set X-Content-Type-Options "nosniff"
-        Header always set X-XSS-Protection "1; mode=block"
         Header always set Referrer-Policy "strict-origin-when-cross-origin"
+        Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'self'; style-src 'self' 'unsafe-inline'"
+        Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"
+        Header always set Cross-Origin-Opener-Policy "same-origin"
+        Header always set Cross-Origin-Resource-Policy "same-origin"
+        Header always unset X-Powered-By
     </IfModule>

If you load assets from CDNs, extend CSP script-src/style-src/img-src accordingly.


3-6: Add ServerName to avoid AH00558 warnings

Prevents startup noise and ensures proper vhost matching.

 <VirtualHost *:80>
-    ServerAdmin webmaster@localhost
+    ServerAdmin webmaster@localhost
+    ServerName localhost
docker/requirements/views/components/category-section.php (4)

9-10: Guard against missing summary keys and clamp percent

Prevents notices and keeps percent within 0–100.

-$summary = $category['summary'];
-$successRate = $summary['total'] > 0 ? round(($summary['passed'] / $summary['total']) * 100, 1) : 0;
+$summary = $category['summary'] ?? ['total' => 0, 'passed' => 0];
+$successRate = ($summary['total'] ?? 0) > 0
+    ? min(100, round((($summary['passed'] ?? 0) / $summary['total']) * 100, 1))
+    : 0;

29-29: Add accessibility attributes to progress bar

Improves screen reader support.

-                        <div class="progress-bar bg-success" style="width: <?= $successRate ?>%"></div>
+                        <div class="progress-bar bg-success"
+                             role="progressbar"
+                             aria-valuenow="<?= $successRate ?>"
+                             aria-valuemin="0"
+                             aria-valuemax="100"
+                             style="width: <?= $successRate ?>%"></div>

114-114: Escape status label text

Minor hardening.

-                                        <?= ucfirst($requirement['status']) ?>
+                                        <?= ViewRenderer::escape(ucfirst((string)($requirement['status'] ?? ''))) ?>

135-211: Move inline styles to the shared CSS asset

Keeps views lean and caches CSS effectively.

I can draft the corresponding rules in docker/requirements/assets/css/app.css and update the view to drop the <style> block—say the word.

docker/configs/php/prod.ini (4)

16-16: Modernize error_reporting mask.

E_STRICT is obsolete. Optionally exclude user deprecations.

-error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
+error_reporting = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED

30-31: Samesite=Strict and cookie_secure=1 can block auth behind proxies.

Strict can break OAuth/SSO; cookie_secure=1 drops cookies if PHP doesn’t detect HTTPS behind a reverse proxy. Verify deployment headers (X-Forwarded-Proto) or adjust.

-session.cookie_samesite = Strict
+session.cookie_samesite = Lax

If staying Strict, ensure proxy HTTPS detection is correctly configured.


44-45: Doc comments stripped may break libraries using annotations/reflection.

Consider keeping comments unless you’re certain they’re unused.

-opcache.save_comments = 0
+opcache.save_comments = 1

47-49: Nit: JIT note.

JIT has existed since PHP 8.0; the comment “PHP 8.4+” is misleading.

-; JIT for PHP 8.4+
+; JIT (PHP 8+)
docker/configs/php/dev.ini (1)

48-54: Make Xdebug host resolution portable.

On Linux, host.docker.internal may not resolve. Let Xdebug auto-detect.

 [xdebug]
 xdebug.client_host = host.docker.internal
 xdebug.client_port = 9003
 xdebug.idekey = PHPSTORM
 xdebug.log_level = 0
 xdebug.mode = debug,develop,coverage
 xdebug.start_with_request = yes
+; auto-detect client on Linux
+xdebug.discover_client_host = 1
docker/configs/php/full.ini (1)

49-56: Same portability tweak for Xdebug.

 [xdebug]
 xdebug.client_host = host.docker.internal
 xdebug.client_port = 9003
 xdebug.idekey = PHPSTORM
 xdebug.log_level = 1
 xdebug.mode = debug,develop,coverage,profile
 xdebug.output_dir = /tmp/xdebug
 xdebug.start_with_request = yes
+; auto-detect client on Linux
+xdebug.discover_client_host = 1
docker/scripts/install-mssql.sh (2)

61-68: Slim image: remove php-pear and curl after build.

They’re not needed at runtime.

 apt-get remove -y --purge \
     gnupg \
     apt-transport-https \
     php${PHP_VER}-dev \
     build-essential \
+    php-pear \
+    curl \

2-2: Stricter shell options improve robustness.

-set -e
+set -Eeuo pipefail
docker/scripts/install-oracle.sh (3)

9-16: Trim runtime by removing transient tools.

wget/unzip aren’t needed at runtime; uninstall after use.

 apt-get update && apt-get install -y --no-install-recommends \
     libaio1t64 \
     wget \
     unzip \
     && apt-get clean \
     && rm -rf /var/lib/apt/lists/*

After extraction:

+apt-get remove -y --purge wget unzip && apt-get autoremove -y && apt-get clean

27-35: Add checksum verification for Oracle downloads.

Reduce supply-chain risk by validating ZIPs.


46-49: LD_LIBRARY_PATH export only affects current shell.

You already call ldconfig; the exports are unnecessary unless building immediately (you are). Keep, but consider dropping them after build to avoid polluting environment.

docker/scripts/entrypoint.sh (2)

43-46: Avoid accumulating duplicate ServerName entries

Append only if not already present.

-if [ -n "$APACHE_SERVER_NAME" ]; then
-    echo "ServerName ${APACHE_SERVER_NAME}" >> /etc/apache2/apache2.conf
+if [ -n "$APACHE_SERVER_NAME" ]; then
+    grep -qE "^\\s*ServerName\\s+${APACHE_SERVER_NAME}\\b" /etc/apache2/apache2.conf || \
+      echo "ServerName ${APACHE_SERVER_NAME}" >> /etc/apache2/apache2.conf
 fi

54-73: Xdebug sed may no-op if keys absent; guard file and append defaults

If keys are missing, sed does nothing. Guard the ini file and append when needed.

-if [ "$BUILD_TYPE" = "dev" ] || [ "$BUILD_TYPE" = "full" ]; then
+if [ "$BUILD_TYPE" = "dev" ] || [ "$BUILD_TYPE" = "full" ]; then
     if [ "$XDEBUG_ENABLED" = "true" ]; then
         echo -e "${YELLOW}Enabling Xdebug...${NC}"
         phpenmod xdebug
-        
-        # Update Xdebug settings if provided
-        if [ -n "$XDEBUG_HOST" ]; then
-            sed -i "s/xdebug.client_host.*/xdebug.client_host = ${XDEBUG_HOST}/g" /etc/php/${PHP_VERSION}/mods-available/xdebug.ini
-        fi
+        ini="/etc/php/${PHP_VERSION}/mods-available/xdebug.ini"
+        [ -f "$ini" ] || ini="/etc/php/${PHP_VERSION}/apache2/conf.d/20-xdebug.ini"
+        touch "$ini"
+        # Update Xdebug settings if provided (append if not present)
+        if [ -n "$XDEBUG_HOST" ]; then
+            grep -q '^xdebug.client_host' "$ini" && \
+              sed -i "s|^xdebug.client_host.*|xdebug.client_host = ${XDEBUG_HOST}|" "$ini" || \
+              echo "xdebug.client_host = ${XDEBUG_HOST}" >> "$ini"
+        fi
         if [ -n "$XDEBUG_PORT" ]; then
-            sed -i "s/xdebug.client_port.*/xdebug.client_port = ${XDEBUG_PORT}/g" /etc/php/${PHP_VERSION}/mods-available/xdebug.ini
+            grep -q '^xdebug.client_port' "$ini" && \
+              sed -i "s|^xdebug.client_port.*|xdebug.client_port = ${XDEBUG_PORT}|" "$ini" || \
+              echo "xdebug.client_port = ${XDEBUG_PORT}" >> "$ini"
         fi
         if [ -n "$XDEBUG_MODE" ]; then
-            sed -i "s/xdebug.mode.*/xdebug.mode = ${XDEBUG_MODE}/g" /etc/php/${PHP_VERSION}/mods-available/xdebug.ini
+            grep -q '^xdebug.mode' "$ini" && \
+              sed -i "s|^xdebug.mode.*|xdebug.mode = ${XDEBUG_MODE}|" "$ini" || \
+              echo "xdebug.mode = ${XDEBUG_MODE}" >> "$ini"
         fi
     else

Also applies to: 60-68

docker/requirements/classes/ComponentHelper.php (2)

59-68: getOverallStatus: avoid undefined index notices

Use null coalescing; cast to int.

-    if ($summary['failed'] > 0 || $summary['errors'] > 0) {
+    $failed = (int)($summary['failed'] ?? 0);
+    $errors = (int)($summary['errors'] ?? 0);
+    $warnings = (int)($summary['warnings'] ?? 0);
+    if ($failed > 0 || $errors > 0) {
         return 'danger';
     }
-    if ($summary['warnings'] > 0) {
+    if ($warnings > 0) {
         return 'warning';
     }
     return 'success';

73-89: getStatusMessage: avoid undefined index notices; minor grammar tweak

Coalesce values; keep message stable.

-    $total = $summary['total'];
-    $passed = $summary['passed'];
-    $warnings = $summary['warnings'];
-    $failed = $summary['failed'];
+    $total = (int)($summary['total'] ?? 0);
+    $passed = (int)($summary['passed'] ?? 0);
+    $warnings = (int)($summary['warnings'] ?? 0);
+    $failed = (int)($summary['failed'] ?? 0);
docker/requirements/assets/js/app.js (3)

71-88: Anchor selector likely mismatched

data-bs-spy="scroll" is usually on the container, not links. If your links carry this attr intentionally, ignore; otherwise use a more typical selector.

-document.querySelectorAll('a[data-bs-spy="scroll"]').forEach(link => {
+document.querySelectorAll('a[href^="#"]').forEach(link => {

224-245: Export: include app/version metadata and content-type hint

Optional: enrich the export and set an explicit charset.

-        const dataBlob = new Blob([dataStr], {type: 'application/json'});
+        const dataBlob = new Blob([dataStr], {type: 'application/json;charset=utf-8'});

Additionally, consider adding { app: 'yii2-requirements', version: window.appVersion || 'unknown' } into reportData.


126-136: Throttle frequency: consider 150–200ms to reduce work on low-end devices

Minor perf tweak; 100ms is fine, but 150–200ms is usually indistinguishable and cheaper.

-    }, 100));
+    }, 180));
docker/requirements/classes/RequirementsChecker.php (7)

632-639: Remove dead code: unused private evaluateExpression()

This method is no longer used (you moved to direct boolean conditions). Keeping an eval-based helper around is unnecessary risk and noise.

-    /**
-     * Evaluate PHP expression safely
-     */
-    private function evaluateExpression(string $expression): bool
-    {
-        try {
-            return (bool) eval("return $expression;");
-        } catch (Throwable $e) {
-            return false;
-        }
-    }

214-231: Clarify JIT buffer metric naming (it reports total, not “used”)

$metrics['jit_buffer_used'] is set from buffer_size, which represents total JIT buffer size. Either rename to jit_buffer_total (and optionally add jit_buffer_free) or compute “used = total - free” if the free key is available.

-                if (isset($status['jit'])) {
-                    $metrics['jit_buffer_used'] = isset($status['jit']['buffer_size']) 
-                        ? round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB'
-                        : 'Unknown';
-                    $metrics['jit_compiled_funcs'] = $status['jit']['num_traces'] ?? 0;
-                }
+                if (isset($status['jit'])) {
+                    if (isset($status['jit']['buffer_size'])) {
+                        $metrics['jit_buffer_total'] = round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB';
+                    }
+                    // If a "buffer_free" key exists, expose it (compute "used" if both present).
+                    if (isset($status['jit']['buffer_free']) || isset($status['jit']['buffer_free_size'])) {
+                        $free = ($status['jit']['buffer_free'] ?? $status['jit']['buffer_free_size']);
+                        $metrics['jit_buffer_free'] = round($free / 1024 / 1024, 2) . ' MB';
+                        if (isset($status['jit']['buffer_size'])) {
+                            $metrics['jit_buffer_used'] = round(($status['jit']['buffer_size'] - $free) / 1024 / 1024, 2) . ' MB';
+                        }
+                    }
+                    $metrics['jit_compiled_traces'] = $status['jit']['num_traces'] ?? 0;
+                }

Please confirm the exact key names present in your PHP build (opcache_get_status()['jit']). Keys vary across versions.


568-574: Normalize boolean ini values robustly

ini_get() returns strings; handle “on/off/true/false/1/0” consistently.

-        $enabled = ini_get('opcache.enable');
-        return $enabled === '1' || $enabled === 1 || $enabled === true;
+        $enabled = ini_get('opcache.enable');
+        return filter_var($enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false;

585-587: Same boolean handling for CLI flag

-        $enabled = ini_get('opcache.enable_cli');
-        return $enabled === '1' || $enabled === 1 || $enabled === true;
+        $enabled = ini_get('opcache.enable_cli');
+        return filter_var($enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE) ?? false;

30-31: Prefer PHP_SAPI over php_sapi_name()

Minor simplification; avoids a function call.

-            'php_sapi' => php_sapi_name(),
+            'php_sapi' => PHP_SAPI,

256-263: Revisit “core” extensions list

unicode isn’t a typical entry from get_loaded_extensions() on PHP 8.x. Consider adjusting baseline “core” set or deriving it dynamically to avoid misleading counts.


272-289: Double‑check messaging vs. base image PHP version

The requirement says “8.1.0 or higher” and the recommendation text mentions upgrading to 8.1. If your Debian Trixie image ships with PHP 8.2/8.3, update the copy to match.

docker/requirements/views/layouts/error.php (4)

5-7: Broaden type to Throwable

Errors (TypeError, Error) won’t render details with the current Exception check. Use Throwable in phpdoc and runtime checks.

- * @var Exception $error
+ * @var Throwable $error

And below:

- <?php if (isset($error) && $error instanceof Exception): ?>
+ <?php if (isset($error) && $error instanceof Throwable): ?>

106-113: Escape line number for consistency (minor)

It’s an int, but for consistency with other fields you can escape/cast.

- <dd class="col-sm-8"><?= ViewRenderer::escape($error->getFile()) ?>:<?= $error->getLine() ?></dd>
+ <dd class="col-sm-8"><?= ViewRenderer::escape($error->getFile()) ?>:<?= ViewRenderer::escape((string)$error->getLine()) ?></dd>

16-18: Optional: add Subresource Integrity (SRI) and crossorigin to CDN links

Improves supply‑chain safety when loading from CDNs.


78-81: Optional: preserve existing query params when switching to JSON

Using ?format=json drops any existing filters. Consider building the URL from location.search to retain params.

docker/requirements/views/layout.php (1)

23-25: Add SRI to CDN assets

Add integrity/crossorigin to Bootstrap CSS/JS and Icons CDN links for supply-chain hardening.

Would you like me to add the correct SRI hashes for the pinned versions?

Also applies to: 79-83

docker/requirements/views/components/header.php (1)

69-74: Add ARIA for progress segments

Improve accessibility by setting aria-label, aria-valuenow/min/max.

-            <div class="progress">
-                <div class="progress-bar bg-success" style="width: <?php echo $successRate; ?>%"></div>
-                <div class="progress-bar bg-warning" style="width: <?php echo $warningRate; ?>%"></div>
-                <div class="progress-bar bg-danger" style="width: <?php echo $errorRate; ?>%"></div>
-            </div>
+            <div class="progress" role="progressbar" aria-label="Requirement status" aria-valuemin="0" aria-valuemax="100">
+                <div class="progress-bar bg-success" style="width: <?= $successRate ?>%" aria-valuenow="<?= (int)$successRate ?>"></div>
+                <div class="progress-bar bg-warning" style="width: <?= $warningRate ?>%" aria-valuenow="<?= (int)$warningRate ?>"></div>
+                <div class="progress-bar bg-danger" style="width: <?= $errorRate ?>%" aria-valuenow="<?= (int)$errorRate ?>"></div>
+            </div>
docker/requirements/views/components/system-info.php (1)

141-151: Avoid instantiating the checker in a view

Consider moving byte-size parsing behind a helper (e.g., ComponentHelper::getByteSize()) or pass precomputed values from the controller to keep view logic thin.

I can refactor this by adding a helper and wiring precomputed memory-limit bytes into the view data.

docker/requirements/views/components/navigation.php (2)

43-53: Remove misused ScrollSpy attributes on links

data-bs-spy="scroll" belongs on the scroll container (e.g., body), not on anchor tags. These attributes here have no effect.

-                <a class="nav-link" href="#overview" data-bs-spy="scroll">
+                <a class="nav-link" href="#overview">
@@
-                <a class="nav-link" href="#system-info" data-bs-spy="scroll">
+                <a class="nav-link" href="#system-info">

26-37: Cast quick stats to int

Ensure numeric output is safe and consistent.

-                <span class="stat-number text-success"><?php echo $summary['passed']; ?></span>
+                <span class="stat-number text-success"><?= (int)($summary['passed'] ?? 0); ?></span>
@@
-                <span class="stat-number text-warning"><?php echo $summary['warnings']; ?></span>
+                <span class="stat-number text-warning"><?= (int)($summary['warnings'] ?? 0); ?></span>
@@
-                <span class="stat-number text-danger"><?php echo $summary['failed']; ?></span>
+                <span class="stat-number text-danger"><?= (int)($summary['failed'] ?? 0); ?></span>
docker/requirements/index.php (2)

68-79: Avoid leaking stack traces by default

Returning full stack traces in production JSON can expose sensitive details. Gate it behind a debug=1 flag or environment variable.

-        echo json_encode([
-            'error' => true,
-            'message' => 'Requirements check failed: ' . $e->getMessage(),
-            'timestamp' => date('c'),
-            'trace' => $e->getTraceAsString()
-        ], JSON_PRETTY_PRINT);
+        $payload = [
+            'error' => true,
+            'message' => 'Requirements check failed: ' . $e->getMessage(),
+            'timestamp' => date('c'),
+        ];
+        if (($_GET['debug'] ?? '') === '1') {
+            $payload['trace'] = $e->getTraceAsString();
+        }
+        echo json_encode($payload, JSON_PRETTY_PRINT);

41-44: Harden response headers

Add X-Content-Type-Options: nosniff and a conservative Referrer-Policy in both HTML and JSON responses.

-        header('Cache-Control: no-cache, must-revalidate');
+        header('Cache-Control: no-cache, must-revalidate');
+        header('X-Content-Type-Options: nosniff');
+        header('Referrer-Policy: no-referrer');
@@
-        header('Cache-Control: no-cache, must-revalidate');
+        header('Cache-Control: no-cache, must-revalidate');
+        header('X-Content-Type-Options: nosniff');
+        header('Referrer-Policy: no-referrer');

Also applies to: 33-39

docker/requirements/views/components/breadcrumbs.php (1)

35-44: Wire Prev/Next controls or remove until implemented.

These buttons are present but no handlers in this file; ensure they’re functional somewhere else or hide them to avoid UX dead ends.

I can add minimal handlers to traverse window.breadcrumbSections and update the DOM if desired.

docker/requirements/views/layouts/main.php (3)

21-21: Guard against undefined indexes in $system.

If build_type is missing, this will emit notices. Use null-coalescing with a sensible default.

-<title>Yii2 Requirements Checker - <?= ViewRenderer::escape(ucfirst($system['build_type'])) ?> Build</title>
+<title>Yii2 Requirements Checker - <?= ViewRenderer::escape(ucfirst($system['build_type'] ?? 'unknown')) ?> Build</title>
...
-<small><?= ViewRenderer::escape(ucfirst($system['build_type'])) ?> Build</small>
+<small><?= ViewRenderer::escape(ucfirst($system['build_type'] ?? 'unknown')) ?> Build</small>
...
-Build: <?= ViewRenderer::escape($system['build_type']) ?>
+Build: <?= ViewRenderer::escape($system['build_type'] ?? 'unknown') ?>

Also applies to: 282-282, 376-376


405-420: Limit “active” class updates to the sidebar nav to avoid clobbering other anchors.

Current code adds active to any hash link (e.g., breadcrumbs), leaving the sidebar without an active item.

-        document.querySelectorAll('a[href^="#"]').forEach(link => {
+        document.querySelectorAll('a[href^="#"]').forEach(link => {
             link.addEventListener('click', (e) => {
                 e.preventDefault();
                 const target = document.querySelector(link.getAttribute('href'));
                 if (target) {
                     target.scrollIntoView({ behavior: 'smooth', block: 'start' });
-                    
-                    // Update active nav
-                    document.querySelectorAll('.nav-link').forEach(navLink => {
-                        navLink.classList.remove('active');
-                    });
-                    link.classList.add('active');
+                    // Update active state only for sidebar nav links
+                    if (link.matches('.sidebar .nav .nav-link')) {
+                      document.querySelectorAll('.sidebar .nav .nav-link').forEach(navLink => {
+                        navLink.classList.remove('active');
+                      });
+                      link.classList.add('active');
+                    }
                 }
             });
         });

445-473: Make mobile sidebar responsive to viewport changes.

Mobile overlay/toggle is only initialized on first load if window.innerWidth <= 991. Handle resize via matchMedia to avoid stale UI when rotating or resizing.

docker/requirements/views/components/summary-cards.php (2)

96-100: Add progressbar ARIA attributes for accessibility.

Expose roles and values so assistive tech can interpret the progress breakdown.

-                        <div class="progress mb-2" style="height: 8px;">
-                            <div class="progress-bar bg-success" style="width: <?= $successRate ?>%"></div>
-                            <div class="progress-bar bg-warning" style="width: <?= $summary['total'] > 0 ? round(($summary['warnings'] / $summary['total']) * 100, 1) : 0 ?>%"></div>
-                            <div class="progress-bar bg-danger" style="width: <?= $summary['total'] > 0 ? round(($summary['failed'] / $summary['total']) * 100, 1) : 0 ?>%"></div>
-                        </div>
+                        <div class="progress mb-2" style="height: 8px;">
+                            <div class="progress-bar bg-success" role="progressbar" aria-label="Passed"
+                                 style="width: <?= $successRate ?>%" aria-valuenow="<?= $successRate ?>" aria-valuemin="0" aria-valuemax="100"></div>
+                            <?php $warn = $summary['total'] > 0 ? round(($summary['warnings'] / $summary['total']) * 100, 1) : 0; ?>
+                            <div class="progress-bar bg-warning" role="progressbar" aria-label="Warnings"
+                                 style="width: <?= $warn ?>%" aria-valuenow="<?= $warn ?>" aria-valuemin="0" aria-valuemax="100"></div>
+                            <?php $fail = $summary['total'] > 0 ? round(($summary['failed'] / $summary['total']) * 100, 1) : 0; ?>
+                            <div class="progress-bar bg-danger" role="progressbar" aria-label="Failed"
+                                 style="width: <?= $fail ?>%" aria-valuenow="<?= $fail ?>" aria-valuemin="0" aria-valuemax="100"></div>
+                        </div>

7-7: Guard against missing keys in $summary.

If any of total/passed are absent, notices occur. Optional: normalize $summary with defaults before computing $successRate.

docker/requirements/views/partials/status-alert.php (1)

141-147: Make highlight re-triggerable on repeated clicks.

Clear the animation style after it ends; otherwise subsequent clicks may not highlight.

Apply:

 function scrollToFirstError() {
     const firstError = document.querySelector('.requirement-item.failed');
     if (firstError) {
         firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
-        firstError.style.animation = 'highlight 2s ease-in-out';
+        firstError.style.animation = 'highlight 2s ease-in-out';
+        firstError.addEventListener('animationend', () => {
+            firstError.style.animation = '';
+        }, { once: true });
     }
 }
@@
 function scrollToFirstWarning() {
     const firstWarning = document.querySelector('.requirement-item.warning');
     if (firstWarning) {
         firstWarning.scrollIntoView({ behavior: 'smooth', block: 'center' });
-        firstWarning.style.animation = 'highlight 2s ease-in-out';
+        firstWarning.style.animation = 'highlight 2s ease-in-out';
+        firstWarning.addEventListener('animationend', () => {
+            firstWarning.style.animation = '';
+        }, { once: true });
     }
 }

Also applies to: 149-155

docker/requirements/views/components/footer.php (2)

236-246: Use a reliable reload and align the action name with behavior.

window.location.reload(true) is deprecated and removing a couple of localStorage keys isn’t “clearing cache”.

Apply:

-function clearCache() {
-    if (confirm('Clear browser cache for this page? This will refresh the page.')) {
-        // Clear localStorage
-        localStorage.removeItem('theme');
-        localStorage.removeItem('viewMode');
-        
-        // Force refresh with cache bypass
-        window.location.reload(true);
-    }
-}
+function clearCache() {
+    if (confirm('Reset saved preferences for this page and refresh?')) {
+        localStorage.removeItem('theme');
+        localStorage.removeItem('viewMode');
+        // Cache-busting refresh
+        const url = new URL(window.location.href);
+        url.searchParams.set('cb', Date.now().toString());
+        window.location.replace(url.toString());
+    }
+}

257-271: Guard for missing footer element.

Defensive check prevents errors if the component is used without the footer present.

Apply:

-const footer = document.querySelector('.requirements-footer');
+const footer = document.querySelector('.requirements-footer');
+if (!footer) { return; }
docker/requirements/classes/ViewRenderer.php (2)

83-86: Escape helper is correct; consider nullable input if templates pass non-strings.

Optional: widen signature to ?string and coerce null to empty string.

Example:

-public static function escape(string $text): string
+public static function escape(?string $text): string
 {
-    return htmlspecialchars($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
+    return htmlspecialchars((string)$text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

17-25: Global data persistence across long-lived runtimes.

If this ever runs under a long-lived PHP process (Swoole/RoadRunner), expose a resetGlobalData() to avoid data bleed.

Proposed addition (outside current hunks):

public static function resetGlobalData(): void
{
    self::$globalData = [];
}
Dockerfile.apache (4)

17-36: Remove duplicated package (netcat-openbsd).

You install netcat-openbsd twice; drop one to keep layers lean.

 RUN apt-get update && apt-get install -y --no-install-recommends \
     apache2 \
     libapache2-mod-php${PHP_VERSION} \
     php${PHP_VERSION}-cli \
     php${PHP_VERSION}-common \
     php${PHP_VERSION}-curl \
     php${PHP_VERSION}-mbstring \
     php${PHP_VERSION}-xml \
     php${PHP_VERSION}-zip \
     php${PHP_VERSION}-intl \
     php${PHP_VERSION}-bcmath \
     php${PHP_VERSION}-opcache \
     ca-certificates \
     curl \
     unzip \
-    netcat-openbsd \
     netcat-openbsd \

80-98: Asset builder stage is unused (dead build time).

Nothing is copied from asset-builder; it adds time/attack surface. Remove it or wire its artifacts into later stages.

Option A (remove):

-###########################################
-# Stage 3: Asset Builder (Node.js/NPM)
-###########################################
-FROM node:20-slim AS asset-builder
-
-WORKDIR /build
-
-# Install composer for foxy integration
-RUN apt-get update && apt-get install -y --no-install-recommends \
-    curl \
-    git \
-    unzip \
-    netcat-openbsd \
-    && curl -sS https://getcomposer.org/installer | php -- \
-        --install-dir=/usr/local/bin \
-        --filename=composer \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/*
-
-# Pre-install foxy globally to speed up builds
-RUN composer global require php-forge/foxy

Option B (keep): copy /root/.composer from asset-builder into dev/full to reuse foxy cache.


268-276: Validate config paths exist at build-time.

Ensure docker/configs/php/{dev,full,prod}.ini and apache files exist, or the build will fail for certain BUILD_TYPE values.

If you want the image to build even when a profile’s ini is missing, guard with multi-stage COPY --from trick or ADD only what exists.


287-293: Confirm /health is actually served.

Healthcheck hits /health, but the Dockerfile only copies a requirements template. Make sure entrypoint or vhost routes /health; otherwise health will flap.

If missing, add a lightweight /health PHP file under web/ and wire in vhost.

docker-compose.yml (2)

226-236: Pin Oracle image tag and consider a modern XE.

latest is volatile; prefer a fixed digest or version to keep CI reproducible. Also 11g is EOL; if possible use a maintained XE image/version.


1-1: Add trailing newline; satisfy yamllint.

Ends without newline; add one to silence tooling.

-  oracle_data:
+  oracle_data:
+

Also applies to: 241-251

docker/requirements/Checker.php (2)

589-601: Handle units robustly; support uppercase and 'B' suffix gracefully.

Current parser ignores bytes suffix and relies on last char only. This is okay, but consider normalizing unexpected inputs.

If you want, I can provide a stricter parser using filter_var + regex.


625-631: $result assignment is used by included template; mark intent.

Static analyzers flag it as unused. Add a comment to clarify or inline into include.

-        $result = $this->result;
+        $result = $this->result; // used by template.php
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a66d35e and e7be2db.

📒 Files selected for processing (39)
  • .editorconfig (1 hunks)
  • .gitattributes (1 hunks)
  • .github/CODE_OF_CONDUCT.md (1 hunks)
  • .github/FUNDING.yml (1 hunks)
  • .github/ISSUE_TEMPLATE.md (1 hunks)
  • .github/PULL_REQUEST_TEMPLATE.md (1 hunks)
  • .github/dependabot.yml (1 hunks)
  • .gitignore (1 hunks)
  • Dockerfile.apache (1 hunks)
  • LICENSE (0 hunks)
  • LICENSE.md (1 hunks)
  • docker-compose.yml (1 hunks)
  • docker/configs/apache/apache2.conf (1 hunks)
  • docker/configs/apache/vhost.conf (1 hunks)
  • docker/configs/php/dev.ini (1 hunks)
  • docker/configs/php/full.ini (1 hunks)
  • docker/configs/php/prod.ini (1 hunks)
  • docker/configs/php/xdebug.ini (1 hunks)
  • docker/requirements/Checker.php (1 hunks)
  • docker/requirements/assets/css/app.css (1 hunks)
  • docker/requirements/assets/js/app.js (1 hunks)
  • docker/requirements/classes/ComponentHelper.php (1 hunks)
  • docker/requirements/classes/RequirementsChecker.php (1 hunks)
  • docker/requirements/classes/ViewRenderer.php (1 hunks)
  • docker/requirements/index.php (1 hunks)
  • docker/requirements/views/components/breadcrumbs.php (1 hunks)
  • docker/requirements/views/components/category-section.php (1 hunks)
  • docker/requirements/views/components/footer.php (1 hunks)
  • docker/requirements/views/components/header.php (1 hunks)
  • docker/requirements/views/components/navigation.php (1 hunks)
  • docker/requirements/views/components/summary-cards.php (1 hunks)
  • docker/requirements/views/components/system-info.php (1 hunks)
  • docker/requirements/views/layout.php (1 hunks)
  • docker/requirements/views/layouts/error.php (1 hunks)
  • docker/requirements/views/layouts/main.php (1 hunks)
  • docker/requirements/views/partials/status-alert.php (1 hunks)
  • docker/scripts/entrypoint.sh (1 hunks)
  • docker/scripts/install-mssql.sh (1 hunks)
  • docker/scripts/install-oracle.sh (1 hunks)
💤 Files with no reviewable changes (1)
  • LICENSE
🧰 Additional context used
🪛 LanguageTool
.github/CODE_OF_CONDUCT.md

[style] ~5-~5: Consider a more concise word here.
Context: ...rs and maintainers of this project, and in order to keep community open and welcoming, we a...

(IN_ORDER_TO_PREMIUM)


[grammar] ~5-~5: There might be a mistake here.
Context: ...ainers of this project, and in order to keep community open and welcoming, we ask to...

(QB_NEW_EN)


[grammar] ~5-~5: There might be a mistake here.
Context: ... community open and welcoming, we ask to respect all community members. ## Our S...

(QB_NEW_EN)


[grammar] ~12-~12: There might be a mistake here.
Context: ...empathy and kindness toward other people * Being respectful of differing opinions, ...

(QB_NEW_EN)


[grammar] ~13-~13: There might be a mistake here.
Context: ...ng opinions, viewpoints, and experiences * Giving and gracefully accepting construc...

(QB_NEW_EN)


[grammar] ~14-~14: There might be a mistake here.
Context: ...acefully accepting constructive feedback * Accepting responsibility and apologizing...

(QB_NEW_EN)


[grammar] ~15-~15: There might be a mistake here.
Context: ...stakes, and learning from the experience * Focusing on what is best not just for us...

(QB_NEW_EN)


[grammar] ~20-~20: There might be a mistake here.
Context: ...sexual attention or advances of any kind * Trolling, insulting or derogatory commen...

(QB_NEW_EN)


[style] ~21-~21: Try using a synonym here to strengthen your wording.
Context: ...ind * Trolling, insulting or derogatory comments, and personal or political attacks * Pu...

(COMMENT_REMARK)


[grammar] ~21-~21: There might be a mistake here.
Context: ...ments, and personal or political attacks * Public or private harassment * Publishin...

(QB_NEW_EN)


[grammar] ~22-~22: There might be a mistake here.
Context: ...l attacks * Public or private harassment * Publishing others' private information, ...

(QB_NEW_EN)


[grammar] ~23-~23: There might be a mistake here.
Context: ...dress, without their explicit permission * Other conduct which could reasonably be ...

(QB_NEW_EN)


[grammar] ~29-~29: There might be a mistake here.
Context: ...m inappropriate, threatening, offensive, or harmful. Core team members have the ...

(QB_NEW_EN)


[grammar] ~32-~32: There might be a mistake here.
Context: ...ect comments, commits, code, wiki edits, issues, and other contributions that are...

(QB_NEW_EN)


[grammar] ~38-~38: There might be a mistake here.
Context: ...an individual is officially representing the community in public spaces. Examples...

(QB_NEW_EN)


[grammar] ~39-~39: There might be a mistake here.
Context: ...mmunity include using an official e-mail address, posting via an official social ...

(QB_NEW_EN)


[grammar] ~40-~40: There might be a mistake here.
Context: ...official forum or acting as an appointed representative at an online or offline e...

(QB_NEW_EN)


[grammar] ~45-~45: There might be a mistake here.
Context: ...ted by contacting core team members. All complaints will be reviewed and investig...

(QB_NEW_EN)


[grammar] ~52-~52: There might be a mistake here.
Context: ...ing the consequences for any action they deem in violation of this Code of Conduc...

(QB_NEW_EN)


[grammar] ~82-~82: There might be a mistake here.
Context: ...dards, including sustained inappropriate behavior, harassment of an individual, o...

(QB_NEW_EN)


[grammar] ~89-~89: There might be a mistake here.
Context: ...nt][homepage], version 2.1, available at [https://www.contributor-covenant.org/ve...

(QB_NEW_EN)


[grammar] ~95-~95: There might be a mistake here.
Context: ...faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/tr...

(QB_NEW_EN)

.github/PULL_REQUEST_TEMPLATE.md

[grammar] ~3-~3: There might be a mistake here.
Context: ...----------- | --- | Is bugfix? | ✔️/❌ | New feature? | ✔️/❌ | Breaks BC? |...

(QB_NEW_EN)


[grammar] ~4-~4: There might be a mistake here.
Context: ...bugfix? | ✔️/❌ | New feature? | ✔️/❌ | Breaks BC? | ✔️/❌ | Fixed issues |...

(QB_NEW_EN)


[grammar] ~5-~5: There might be a mistake here.
Context: ... feature? | ✔️/❌ | Breaks BC? | ✔️/❌ | Fixed issues | <!-- comma-separated l...

(QB_NEW_EN)

LICENSE.md

[grammar] ~10-~10: There might be a mistake here.
Context: ...conditions and the following disclaimer. * Redistributions in binary form must repr...

(QB_NEW_EN)


[grammar] ~13-~13: There might be a mistake here.
Context: ...aterials provided with the distribution. * Neither the name of Yii2 Extensions (Ter...

(QB_NEW_EN)


[grammar] ~18-~18: There might be a mistake here.
Context: ...GHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLU...

(QB_NEW_EN)


[grammar] ~21-~21: There might be a mistake here.
Context: ...IGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIA...

(QB_NEW_EN)


[grammar] ~26-~26: There might be a mistake here.
Context: ...RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBI...

(QB_NEW_EN)


[grammar] ~27-~27: There might be a mistake here.
Context: ...VISED OF THE POSSIBILITY OF SUCH DAMAGE.

(QB_NEW_EN)

.github/ISSUE_TEMPLATE.md

[grammar] ~13-~13: There might be a mistake here.
Context: ...n | 1.0.? | PHP version | | Operating system |

(QB_NEW_EN)

🪛 PHPMD (2.15.0)
docker/requirements/classes/RequirementsChecker.php

500-500: Avoid unused local variables such as '$output'. (Unused Code Rules)

(UnusedLocalVariable)


632-639: Avoid unused private methods such as 'evaluateExpression'. (Unused Code Rules)

(UnusedPrivateMethod)

docker/requirements/Checker.php

555-555: Avoid unused local variables such as '$output'. (Unused Code Rules)

(UnusedLocalVariable)


607-610: Avoid unused private methods such as 'evaluateExpression'. (Unused Code Rules)

(UnusedPrivateMethod)


629-629: Avoid unused local variables such as '$result'. (Unused Code Rules)

(UnusedLocalVariable)

🪛 YAMLlint (1.37.1)
docker-compose.yml

[error] 251-251: no new line character at the end of file

(new-line-at-end-of-file)

🔇 Additional comments (14)
.github/FUNDING.yml (1)

1-3: LGTM — valid GitHub Sponsors config.

Recognized format; should enable the sponsor button for terabytesoftw.

.gitignore (1)

6-6: Reconsider ignoring composer.lock.

For apps/images, committing composer.lock improves reproducibility; for libraries it’s commonly ignored. Pick one intentionally.

docker/requirements/views/components/category-section.php (1)

31-33: No changes needed: getOverallStatus returns valid Bootstrap badge classes
The function only returns 'danger', 'warning', or 'success', all of which map to Bootstrap’s contextual badge colors.

docker/configs/php/full.ini (1)

41-43: Opcache revalidate on every request is heavy.

For “Full Testing” this may be fine, but confirm it’s intentional.

docker/scripts/install-mssql.sh (1)

20-27: Mixing Bookworm repo on Trixie—confirm compatibility.

Using the Debian 12 (bookworm) Microsoft repo on Debian 13 (trixie) can cause ABI issues. Verify runtime with your base image.

docker/requirements/classes/ComponentHelper.php (1)

94-98: Badge escaping dependency: ensure ViewRenderer::escape is available

If ViewRenderer isn’t loaded here, this will fatal. Either import/require it or provide a local fallback.

I can add a local escape() fallback inside this class if you prefer.

docker/requirements/classes/RequirementsChecker.php (1)

481-491: checkMemoryLimit: good handling of “-1” unlimited

Unlimited is correctly treated as pass. LGTM.

docker/configs/apache/apache2.conf (2)

29-33: Good hardening defaults

ServerTokens Prod, ServerSignature Off, and TraceEnable Off are solid production settings.


52-54: Rewrite rules confirmed in vhost.conf
The Directory /var/www/app/web in docker/configs/apache/vhost.conf enables AllowOverride All and includes the necessary RewriteEngine On and RewriteRule directives, so disabling .htaccess in the main config won’t break URL rewriting.

docker/requirements/views/layout.php (1)

49-58: Ignore missing anchor IDs The #overview and #system-info targets are defined in the parent layout (docker/requirements/views/layouts/main.php), so the navigation links already work as intended.

Likely an incorrect or invalid review comment.

docker/requirements/views/components/breadcrumbs.php (1)

51-58: Resolved: ComponentHelper::getCategoryIcon is already safe
Uses a hard-coded map of category names to icon identifiers (only letters, numbers, and hyphens) with a default of “gear,” so no injection risk remains.

docker/requirements/views/partials/status-alert.php (1)

74-108: Nice UX for success state.

Clear copy, accessible actions, and vertical button group read well.

docker/requirements/views/components/footer.php (1)

202-234: Keyboard Shortcuts modal looks solid.

Clean Bootstrap usage and scoped content structure.

docker/requirements/classes/ViewRenderer.php (1)

71-77: Good exception-safe buffering.

ob_start + cleanup + context-rich RuntimeException is appropriate.

Copy link

@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.

Review continued from previous batch...

Copy link

@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.

Actionable comments posted: 3

♻️ Duplicate comments (2)
docker/requirements/Checker.php (2)

129-135: Nice: removed eval-path; conditions are now true booleans.

This resolves the prior “always truthy string” bug.


369-374: Good fix: Composer check uses a real boolean now.

This replaces the old 'eval:' string approach.

🧹 Nitpick comments (5)
docker/requirements/Checker.php (5)

589-604: Guard getByteSize() against empty strings and add types.

Empty input triggers an undefined offset; adding a quick guard prevents that.

-    public function getByteSize($size)
+    public function getByteSize(string $size): int
     {
         $size = trim($size);
+        if ($size === '') {
+            return 0;
+        }
-        $last = strtolower($size[strlen($size)-1]);
+        $last = strtolower($size[strlen($size)-1]);
-        $size = (int) $size;
+        $size = (int) $size;

616-626: PHPMD false-positive: $result is used by the included template.

Suppress the warning at method level.

-    /**
-     * Render HTML output
-     */
+    /**
+     * Render HTML output
+     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+     */
     public function renderHtml()
     {
         if (!$this->result) {
             $this->check();
         }
 
         $result = $this->result;
         include __DIR__ . '/template.php';
     }

42-50: Make uptime detection OS-aware and resilient to read failures.

Avoids warnings on non-Linux or rare read errors.

-        if (file_exists('/proc/uptime')) {
-            $uptime = file_get_contents('/proc/uptime');
-            $uptime = (float) explode(' ', $uptime)[0];
-            return $this->formatUptime($uptime);
-        }
+        if (PHP_OS_FAMILY === 'Linux' && is_readable('/proc/uptime')) {
+            $raw = @file_get_contents('/proc/uptime');
+            if ($raw !== false) {
+                $uptime = (float) explode(' ', $raw)[0];
+                return $this->formatUptime($uptime);
+            }
+        }
         return 'Unknown';

55-62: Add type hints to formatUptime() (and consider reusing the shared formatter).

Keeps behavior consistent with classes/ComponentHelper::formatUptime() and improves static analysis.

-    private function formatUptime($seconds)
+    private function formatUptime(float $seconds): string
     {
-        $days = floor($seconds / 86400);
-        $hours = floor(($seconds % 86400) / 3600);
-        $minutes = floor(($seconds % 3600) / 60);
+        $seconds = (int)$seconds;
+        $days = intdiv($seconds, 86400);
+        $hours = intdiv($seconds % 86400, 3600);
+        $minutes = intdiv($seconds % 3600, 60);
 
         return sprintf('%dd %dh %dm', $days, $hours, $minutes);
     }

5-11: Avoid duplication with classes/RequirementsChecker.php.

This class mirrors logic already present in docker/requirements/classes/RequirementsChecker.php (uptime, byte-size/compare, OPcache checks). Consider consolidating to a single source of truth to prevent drift.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e7be2db and d1a25a0.

📒 Files selected for processing (3)
  • Dockerfile.apache (1 hunks)
  • LICENSE (1 hunks)
  • docker/requirements/Checker.php (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • LICENSE
🚧 Files skipped from review as they are similar to previous changes (1)
  • Dockerfile.apache
🧰 Additional context used
🧬 Code graph analysis (1)
docker/requirements/Checker.php (2)
docker/requirements/classes/RequirementsChecker.php (22)
  • __construct (16-21)
  • initSystemInfo (26-41)
  • getUptime (46-61)
  • formatUptime (66-73)
  • check (78-131)
  • getDefaultRequirements (269-478)
  • normalizeRequirement (152-163)
  • processRequirement (136-147)
  • runPerformanceTest (168-176)
  • getOpcacheMetrics (181-237)
  • getMemoryMetrics (242-249)
  • getExtensionMetrics (254-264)
  • checkOpcacheLoaded (553-561)
  • checkMemoryLimit (483-491)
  • checkOpcacheEnabled (566-574)
  • checkOpcacheCliEnabled (579-587)
  • checkJitEnabled (619-627)
  • checkCommandExists (496-505)
  • compareByteSize (510-523)
  • getByteSize (528-548)
  • getResult (644-647)
  • getJson (652-659)
docker/requirements/classes/ComponentHelper.php (1)
  • formatUptime (138-150)
🪛 PHPMD (2.15.0)
docker/requirements/Checker.php

557-557: Avoid unused local variables such as '$void'. (Unused Code Rules)

(UnusedLocalVariable)


624-624: Avoid unused local variables such as '$result'. (Unused Code Rules)

(UnusedLocalVariable)

Copy link

@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.

Actionable comments posted: 1

♻️ Duplicate comments (1)
docker/requirements/Checker.php (1)

189-199: Harden OPcache metrics: guard missing keys to avoid notices.

Some builds omit sub-keys; direct indexing can emit notices. Use null coalescing/isset with sane defaults.

Apply:

-        $metrics = [
-            'enabled' => $status['opcache_enabled'],
-            'memory_usage' => round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . ' MB',
-            'memory_free' => round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . ' MB',
-            'memory_wasted' => round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 2) . ' MB',
-            'cached_files' => $status['opcache_statistics']['num_cached_scripts'],
-            'max_cached_files' => ini_get('opcache.max_accelerated_files'),
-            'hit_rate' => round($status['opcache_statistics']['opcache_hit_rate'], 2) . '%',
-            'cache_misses' => $status['opcache_statistics']['misses'],
-            'cache_hits' => $status['opcache_statistics']['hits']
-        ];
+        $mu = $status['memory_usage'] ?? [];
+        $st = $status['opcache_statistics'] ?? [];
+        $metrics = [
+            'enabled' => $status['opcache_enabled'] ?? false,
+            'memory_usage' => isset($mu['used_memory']) ? round($mu['used_memory'] / 1048576, 2) . ' MB' : 'Unknown',
+            'memory_free' => isset($mu['free_memory']) ? round($mu['free_memory'] / 1048576, 2) . ' MB' : 'Unknown',
+            'memory_wasted' => isset($mu['wasted_memory']) ? round($mu['wasted_memory'] / 1048576, 2) . ' MB' : 'Unknown',
+            'cached_files' => $st['num_cached_scripts'] ?? 0,
+            'max_cached_files' => (int) (ini_get('opcache.max_accelerated_files') ?: 0),
+            'hit_rate' => isset($st['opcache_hit_rate']) ? round($st['opcache_hit_rate'], 2) . '%' : '0%',
+            'cache_misses' => $st['misses'] ?? 0,
+            'cache_hits' => $st['hits'] ?? 0,
+        ];
-            if (isset($status['jit'])) {
-                $metrics['jit_buffer_used'] = round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB';
-                $metrics['jit_compiled_funcs'] = $status['jit']['num_traces'];
-            }
+            if (isset($status['jit'])) {
+                $jit = $status['jit'];
+                $metrics['jit_buffer_used'] = isset($jit['buffer_size'])
+                    ? round($jit['buffer_size'] / 1048576, 2) . ' MB' : 'Unknown';
+                $metrics['jit_compiled_funcs'] = $jit['num_traces'] ?? 0;
+            }

Also applies to: 211-214

🧹 Nitpick comments (7)
docker/requirements/Checker.php (7)

618-628: Silence false positive on $result and add return type.

The template consumes $result. Add suppression and a void return.

Apply:

-    /**
-     * Render HTML output
-     */
-    public function renderHtml()
+    /**
+     * Render HTML output
+     * @SuppressWarnings(PHPMD.UnusedLocalVariable) // consumed by template.php
+     */
+    public function renderHtml(): void
     {
         if (!$this->result) {
             $this->check();
         }
 
         $result = $this->result;
         include __DIR__ + '/template.php';
     }

Note: keep the include path operator as concatenation (.). If + here is a typo, correct to . in your patch.


26-26: Prefer PHP_SAPI constant over php_sapi_name().

Minor speed/readability win; no behavior change.

Apply:

-            'php_sapi' => php_sapi_name(),
+            'php_sapi' => PHP_SAPI,

537-545: Type-hint memory-limit check and tighten contract.

Clarify input/return types and auto-handle unchecked state.

Apply:

-    public function checkMemoryLimit($minimumLimit)
+    public function checkMemoryLimit(string|int $minimumLimit): bool
     {
         $memoryLimit = ini_get('memory_limit');
         if ($memoryLimit === '-1') {
             return true; // Unlimited
         }
 
         return $this->compareByteSize($memoryLimit, $minimumLimit, '>=');
     }

567-586: Add types for size helpers; handle unexpected formats safely.

Expose intent and avoid accidental int coercions.

Apply:

-    public function compareByteSize($a, $b, $operator = '>=')
+    public function compareByteSize(string|int $a, string|int $b, string $operator = '>='): bool
     {
         $bytesA = $this->getByteSize($a);
         $bytesB = $this->getByteSize($b);
-    public function getByteSize($size)
+    public function getByteSize(string|int $size): int
     {
-        $size = trim($size);
-        $last = strtolower($size[strlen($size)-1]);
-        $size = (int) $size;
+        if (is_int($size)) {
+            return $size;
+        }
+        $size = trim($size);
+        if ($size === '') {
+            return 0;
+        }
+        $last = strtolower($size[strlen($size)-1]);
+        $size = (int) $size;
 
         switch($last) {
             case 'g':
                 $size *= 1024;
             case 'm':
                 $size *= 1024;
             case 'k':
                 $size *= 1024;
         }
 
         return $size;
     }

Also applies to: 591-607


242-247: Core extensions list: drop non-existent 'unicode'.

It inflates “additional” count on modern PHP. Consider removing it.

Apply:

-        $core = ['Core', 'date', 'libxml', 'pcre', 'unicode', 'filter', 'SPL', 'session', 'standard'];
+        $core = ['Core', 'date', 'libxml', 'pcre', 'filter', 'SPL', 'session', 'standard'];

633-640: Add JSON_UNESCAPED_UNICODE; optional throws for errors.

Prevents Unicode escaping; consider throws if you want strictness.

Apply:

-        return json_encode($this->result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
+        return json_encode($this->result, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

67-76: Add method signatures to solidify the public API.

Union types are available; returning self eases chaining; auto-check in getResult helps.

Apply:

-    public function check($requirements = null)
+    public function check(array|string|null $requirements = null): self
-        return $this;
+        return $this;
-    public function getResult()
+    public function getResult(): array
     {
-        return $this->result;
+        if ($this->result === null) {
+            $this->check();
+        }
+        return $this->result;
     }

Also applies to: 123-124, 612-616

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d1a25a0 and ad610fd.

📒 Files selected for processing (3)
  • docker/requirements/Checker.php (1 hunks)
  • docker/scripts/install-mssql.sh (1 hunks)
  • docker/scripts/install-oracle.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • docker/scripts/install-mssql.sh
  • docker/scripts/install-oracle.sh
🧰 Additional context used
🪛 PHPMD (2.15.0)
docker/requirements/Checker.php

559-559: Avoid unused local variables such as '$_'. (Unused Code Rules)

(UnusedLocalVariable)


626-626: Avoid unused local variables such as '$result'. (Unused Code Rules)

(UnusedLocalVariable)

🔇 Additional comments (3)
docker/requirements/Checker.php (3)

129-140: Good cleanup: dropped eval-path and centralized status/metrics.

The status derivation is clear, and metrics are attached only when requested. Nice.


487-495: Robust OPcache detection. LGTM.

Covers core/extension/function paths; good cross-version handling.


500-508: Boolean normalization for OPcache/JIT checks. LGTM.

Using filter_var for ini flags and explicit JIT off-values looks correct.

Also applies to: 512-520, 524-532

Copy link

@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.

Actionable comments posted: 5

♻️ Duplicate comments (2)
docker/requirements/views/layouts/main.php (2)

23-26: Avoid bare CDN includes; add SRI/crossorigin or self-host assets.

Add integrity/crossorigin to bootstrap-icons and JS, or ship local assets under the image for hermetic builds and CSP compliance.

Also applies to: 381-382


385-474: Inline JS will be blocked under a strict CSP; move to an external asset or use a nonce.

Extract this block to a static JS file and/or emit a per-request nonce used in both the CSP header and the script tag.

🧹 Nitpick comments (6)
docker/requirements/views/layouts/main.php (2)

312-318: Deduplicate category icon mapping to avoid inconsistencies.

This view uses ComponentHelper::getCategoryIcon; navigation.php defines its own mapping. Prefer the helper everywhere to keep icons consistent.


270-274: Add accessible names to icon-only buttons.

Provide aria-labels for the theme toggle and mobile toggle for screen readers.

-        <button class="btn btn-outline-secondary btn-sm" type="button" id="themeToggle">
+        <button class="btn btn-outline-secondary btn-sm" type="button" id="themeToggle" aria-label="Toggle theme">
-            toggleBtn.innerHTML = '<i class="bi bi-list"></i>';
+            toggleBtn.innerHTML = '<i class="bi bi-list" aria-hidden="true"></i>';
+            toggleBtn.setAttribute('aria-label', 'Toggle navigation');

Also applies to: 455-473

docker/requirements/Checker.php (4)

55-62: Add types to formatUptime() and use intdiv for clarity.

-    private function formatUptime($seconds)
-    {
-        $days = floor($seconds / 86400);
-        $hours = floor(($seconds % 86400) / 3600);
-        $minutes = floor(($seconds % 3600) / 60);
-
-        return sprintf('%dd %dh %dm', $days, $hours, $minutes);
-    }
+    private function formatUptime(float $seconds): string
+    {
+        $s = (int) $seconds;
+        $days = intdiv($s, 86400);
+        $hours = intdiv($s % 86400, 3600);
+        $minutes = intdiv($s % 3600, 60);
+        return sprintf('%dd %dh %dm', $days, $hours, $minutes);
+    }

7-11: Add typed properties (with safe defaults) to match strict_types.

Prevents accidental uninitialized access and improves static analysis.

-final class Checker
+final class Checker
 {
-    private $result;
-    private $buildType;
-    private $phpVersion;
-    private $systemInfo;
+    private array $result = [];
+    private string $buildType;
+    private string $phpVersion;
+    private array $systemInfo = [];

537-546: Add missing parameter/return types for sizing helpers.

Improves correctness with strict_types and documents the contract.

-    public function checkMemoryLimit($minimumLimit)
+    public function checkMemoryLimit(string $minimumLimit): bool
-    public function compareByteSize($a, $b, $operator = '>=')
+    public function compareByteSize(string $a, string $b, string $operator = '>='): bool
-    public function getByteSize($size)
+    public function getByteSize(string $size): int

Also applies to: 567-586, 591-607


620-628: PHPMD false-positive: $result appears unused.

The included template likely consumes $result. Consider adding a local comment or PHPMD suppression to silence the false positive, or switch to a renderer pattern for clarity.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 876b750 and 4807a49.

📒 Files selected for processing (3)
  • docker/requirements/Checker.php (1 hunks)
  • docker/requirements/views/layouts/main.php (1 hunks)
  • docker/scripts/entrypoint.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docker/scripts/entrypoint.sh
🧰 Additional context used
🧬 Code graph analysis (2)
docker/requirements/views/layouts/main.php (3)
docker/requirements/classes/ComponentHelper.php (5)
  • ComponentHelper (9-153)
  • getOverallStatus (59-68)
  • getStatusMessage (73-89)
  • getCategoryIcon (14-28)
  • getStatusIcon (46-54)
docker/requirements/classes/ViewRenderer.php (5)
  • ViewRenderer (9-103)
  • escape (83-86)
  • formatNumber (91-94)
  • formatPercent (99-102)
  • renderComponent (38-41)
docker/requirements/views/components/navigation.php (1)
  • getCategoryIcon (99-112)
docker/requirements/Checker.php (2)
docker/requirements/classes/RequirementsChecker.php (22)
  • __construct (16-21)
  • initSystemInfo (26-41)
  • getUptime (46-61)
  • formatUptime (66-73)
  • check (78-131)
  • getDefaultRequirements (269-478)
  • normalizeRequirement (152-163)
  • processRequirement (136-147)
  • runPerformanceTest (168-176)
  • getOpcacheMetrics (181-237)
  • getMemoryMetrics (242-249)
  • getExtensionMetrics (254-264)
  • checkOpcacheLoaded (553-561)
  • checkMemoryLimit (483-491)
  • checkOpcacheEnabled (566-574)
  • checkOpcacheCliEnabled (579-587)
  • checkJitEnabled (619-627)
  • checkCommandExists (496-505)
  • compareByteSize (510-523)
  • getByteSize (528-548)
  • getResult (644-647)
  • getJson (652-659)
docker/requirements/classes/ComponentHelper.php (1)
  • formatUptime (140-152)
🪛 PHPMD (2.15.0)
docker/requirements/Checker.php

559-559: Avoid unused local variables such as '$_'. (Unused Code Rules)

(UnusedLocalVariable)


626-626: Avoid unused local variables such as '$result'. (Unused Code Rules)

(UnusedLocalVariable)

Copy link

@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.

Actionable comments posted: 3

♻️ Duplicate comments (2)
docker/requirements/Checker.php (2)

557-569: Silence PHPMD unused var in exec capture or rename the var.

PHPMD flags $_ as unused. Add suppression or use a clearly named variable.

     public function checkCommandExists(string $command): bool
     {
         $locator  = (PHP_OS_FAMILY === 'Windows') ? 'where' : 'command -v';
         $redirect = (PHP_OS_FAMILY === 'Windows') ? ' > nul 2>&1' : ' > /dev/null 2>&1';
 
         $arg = escapeshellarg($command);
 
         $code = 1;
-
-        exec("$locator $arg$redirect", $_, $code);
+        /** @SuppressWarnings(PHPMD.UnusedLocalVariable) */
+        $unusedOutput = [];
+        exec("$locator $arg$redirect", $unusedOutput, $code);
 
         return $code === 0;
     }

5-6: Confirm this Checker isn’t a duplicate of classes/RequirementsChecker.php. If unused, delete to avoid drift.

Run the script to verify usage and decide whether to keep or remove this class/template.

#!/bin/bash
# Find any instantiations/usages of this class
rg -nP -C2 '\bnew\s+Checker\s*\('
rg -nP -C2 '\bChecker::' 
# Also check for entry points rendering via this class
rg -nP -C2 '\brenderHtml\s*\('
rg -nP -C2 '\bgetJson\s*\('
🧹 Nitpick comments (5)
docker/requirements/Checker.php (5)

194-205: Avoid notices by guarding optional OPcache status keys.

Accessing nested keys directly may emit notices on some PHP builds/configs.

-        $metrics = [
-            'enabled' => $status['opcache_enabled'],
-            'memory_usage' => round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . ' MB',
-            'memory_free' => round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . ' MB',
-            'memory_wasted' => round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 2) . ' MB',
-            'cached_files' => $status['opcache_statistics']['num_cached_scripts'],
-            'max_cached_files' => ini_get('opcache.max_accelerated_files'),
-            'hit_rate' => round($status['opcache_statistics']['opcache_hit_rate'], 2) . '%',
-            'cache_misses' => $status['opcache_statistics']['misses'],
-            'cache_hits' => $status['opcache_statistics']['hits']
-        ];
+        $metrics = [
+            'enabled' => $status['opcache_enabled'] ?? false,
+            'memory_usage' => isset($status['memory_usage']['used_memory'])
+                ? round($status['memory_usage']['used_memory'] / 1024 / 1024, 2) . ' MB' : 'Unknown',
+            'memory_free' => isset($status['memory_usage']['free_memory'])
+                ? round($status['memory_usage']['free_memory'] / 1024 / 1024, 2) . ' MB' : 'Unknown',
+            'memory_wasted' => isset($status['memory_usage']['wasted_memory'])
+                ? round($status['memory_usage']['wasted_memory'] / 1024 / 1024, 2) . ' MB' : 'Unknown',
+            'cached_files' => $status['opcache_statistics']['num_cached_scripts'] ?? 0,
+            'max_cached_files' => ini_get('opcache.max_accelerated_files'),
+            'hit_rate' => isset($status['opcache_statistics']['opcache_hit_rate'])
+                ? round($status['opcache_statistics']['opcache_hit_rate'], 2) . '%' : '0%',
+            'cache_misses' => $status['opcache_statistics']['misses'] ?? 0,
+            'cache_hits' => $status['opcache_statistics']['hits'] ?? 0
+        ];
-                $metrics['jit_buffer_used'] = round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB';
-                $metrics['jit_compiled_funcs'] = $status['jit']['num_traces'];
+                $metrics['jit_buffer_used'] = isset($status['jit']['buffer_size'])
+                    ? round($status['jit']['buffer_size'] / 1024 / 1024, 2) . ' MB' : 'Unknown';
+                $metrics['jit_compiled_funcs'] = $status['jit']['num_traces'] ?? 0;

Also applies to: 216-219


617-626: Suppress false-positive PHPMD warning for $result used by included template.

The variable is consumed inside the included file; PHPMD can’t see across include boundaries.

-    public function renderHtml(): void
+    /**
+     * Render HTML output
+     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+     */
+    public function renderHtml(): void
     {
         if ($this->result === null) {
             $this->check();
         }
 
         $result = $this->result;
 
         include __DIR__ . '/template.php';
     }

131-142: Tighten type hints for internal helpers for consistency with strict_types.

Add array/string/bool return types to avoid accidental misuse.

-    private function processRequirement(&$requirement): void
+    private function processRequirement(array &$requirement): void
     { ... }
-    private function normalizeRequirement($requirement): array
+    private function normalizeRequirement(array $requirement): array
     { ... }
-    private function runPerformanceTest($testType): array|null
+    private function runPerformanceTest(string $testType): ?array
     { ... }
-    public function checkMemoryLimit($minimumLimit): bool
+    public function checkMemoryLimit(string $minimumLimit): bool
     { ... }
-    public function compareByteSize($a, $b, $operator = '>='): bool
+    public function compareByteSize(string $a, string $b, string $operator = '>='): bool
     { ... }

Also applies to: 147-161, 166-178, 543-552, 574-587


505-513: Add explicit return types to OPcache enablement checks.

Small clarity/readability win.

-    public function checkOpcacheEnabled()
+    public function checkOpcacheEnabled(): bool
     { ... }
-    public function checkOpcacheCliEnabled()
+    public function checkOpcacheCliEnabled(): bool
     { ... }

Also applies to: 517-524


69-79: Validate requirement file path before require and type the parameter.

Prevent warnings on invalid paths; clarify accepted types.

-    public function check($requirements = null): static
+    public function check(array|string|null $requirements = null): static
     {
         if ($requirements === null) {
             $requirements = $this->getDefaultRequirements();
         }
 
-        if (is_string($requirements)) {
-            $requirements = require $requirements;
+        if (is_string($requirements)) {
+            if (!is_file($requirements) || !is_readable($requirements)) {
+                throw new \RuntimeException("Requirements file not found or unreadable: $requirements");
+            }
+            $requirements = require $requirements;
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4807a49 and e8ddd82.

📒 Files selected for processing (1)
  • docker/requirements/Checker.php (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
docker/requirements/Checker.php (2)
docker/requirements/classes/RequirementsChecker.php (17)
  • __construct (16-21)
  • initSystemInfo (26-41)
  • getUptime (46-61)
  • formatUptime (66-73)
  • check (78-131)
  • normalizeRequirement (152-163)
  • processRequirement (136-147)
  • runPerformanceTest (168-176)
  • getOpcacheMetrics (181-237)
  • getMemoryMetrics (242-249)
  • getExtensionMetrics (254-264)
  • checkMemoryLimit (483-491)
  • checkCommandExists (496-505)
  • compareByteSize (510-523)
  • getByteSize (528-548)
  • getResult (644-647)
  • getJson (652-659)
docker/requirements/classes/ComponentHelper.php (1)
  • formatUptime (140-152)
🪛 PHPMD (2.15.0)
docker/requirements/Checker.php

566-566: Avoid unused local variables such as '$_'. (Unused Code Rules)

(UnusedLocalVariable)


623-623: Avoid unused local variables such as '$result'. (Unused Code Rules)

(UnusedLocalVariable)

@terabytesoftw
Copy link
Member Author

@coderabbitai review

Copy link

coderabbitai bot commented Sep 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant