Skip to content

Conversation

@ThomasAFink
Copy link
Member

@ThomasAFink ThomasAFink commented Nov 30, 2025

  • Add PSR-16 cache support to zmsentities module
  • Cache parsed schema objects and JSON strings in Loader
  • Use App::$cache for persistent caching across PHP-FPM workers
  • Add cache hit/set logging via Monolog
  • Update Validator to use cached Loader::asJson() method
  • Cache persists across process restarts and benefits all workers

Pull Request Checklist (Feature Branch to next):

  • Ich habe die neuesten Änderungen aus dem next Branch in meinen Feature-Branch gemergt.
  • Das Code-Review wurde abgeschlossen.
  • Fachliche Tests wurden durchgeführt und sind abgeschlossen.

Summary by CodeRabbit

  • New Features
    • Persistent caching for schema loading to speed repeated access and reduce disk reads.
  • Bug Fixes
    • Better detection and error handling for malformed JSON schema files.
  • Chores
    • Added symfony/cache and psr/simple-cache as runtime dependencies.

✏️ Tip: You can customize this high-level summary in your review settings.

…disk I/O

- Add PSR-16 cache support to zmsentities module
- Cache parsed schema objects and JSON strings in Loader
- Use App::$cache for persistent caching across PHP-FPM workers
- Add cache hit/set logging via Monolog
- Update Validator to use cached Loader::asJson() method
- Cache persists across process restarts and benefits all workers
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 30, 2025

Walkthrough

Adds PSR‑cache-backed schema loading: Loader caches raw JSON and serialized Schema with mtime freshness checks, JSON parse handling, and logging; Validator now loads schema content via Loader::asJson() instead of reading files directly.

Changes

Cohort / File(s) Summary
Dependency Updates
zmsentities/composer.json
Added runtime dependency psr/simple-cache ^3.0 and upgraded symfony/cache from ^5.4 to ^6.0.
Schema Caching Layer
zmsentities/src/Zmsentities/Schema/Loader.php
Added cache helpers (isCacheAvailable, validateCacheMtime, logCacheHit, getCachedSchema, setCachedSchema), JSON parsing helper (parseJsonSchema), and updated asJson() / asArray() to use PSR cache with mtime validation, logging, and caching of raw JSON and reconstructed Schema.
Schema Loading Integration
zmsentities/src/Zmsentities/Schema/Validator.php
Replaced direct file reads (file_get_contents) with Loader::asJson($schemaFilename) and adjusted local variable names to schemaFilename.

Sequence Diagram

sequenceDiagram
    participant Validator
    participant Loader
    participant Cache
    participant Filesystem

    Validator->>Loader: asJson(schemaFilename)
    Loader->>Loader: compute cacheKey & resolve fullPath
    Loader->>Cache: get(cacheKey)
    alt cache hit
        Cache-->>Loader: {data: JSON or serialized Schema, mtime}
        Loader->>Filesystem: stat(fullPath) -> current mtime
        alt mtimes match
            Loader-->>Validator: return cached JSON / reconstructed Schema
            Note right of Loader: optional logCacheHit
        else stale
            Loader->>Filesystem: read fullPath -> JSON
            Filesystem-->>Loader: JSON + mtime
            Loader->>Loader: parseJsonSchema(JSON)
            alt parse success
                Loader->>Cache: set(cacheKey -> {JSON, mtime})
                Loader-->>Validator: return JSON
            else parse fail
                Loader-->>Validator: throw parse error
            end
        end
    else cache miss
        Loader->>Filesystem: read fullPath -> JSON
        Filesystem-->>Loader: JSON + mtime
        Loader->>Loader: parseJsonSchema(JSON)
        alt parse success
            Loader->>Cache: set(cacheKey -> {JSON, mtime})
            Loader-->>Validator: return JSON
        else parse fail
            Loader-->>Validator: throw parse error
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Review cache key construction and namespacing to avoid collisions.
  • Verify mtime validation edge cases (missing files, permission errors, race conditions).
  • Inspect serialization/deserialization of Schema and behavior when cached data format changes.
  • Confirm logging avoids leaking sensitive paths/content and respects environments without cache.

Poem

🐰
I tucked the JSON in a tidy lair,
Heard mtimes ticking, nibbled with care.
Now hops are shorter, reads are few,
I cache, I parse, and humbly chew. 🥕

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding caching for schema files to reduce disk I/O, which aligns perfectly with the changeset that implements PSR-Cache infrastructure and caches both parsed schemas and JSON strings.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat-zmskvr-cache-schemas-in-zmsentities-to-prevent-disk-io-reads

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 149af44 and 5866d63.

⛔ Files ignored due to path filters (1)
  • zmsentities/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • zmsentities/composer.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • zmsentities/composer.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: call-php-unit-tests / zmsdb-test
  • GitHub Check: call-zmsautomation-tests / zmsapiautomation
  • GitHub Check: call-php-unit-tests / zmsapi-test

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.

Copy link
Contributor

@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

🧹 Nitpick comments (3)
zmsentities/src/Zmsentities/Schema/Loader.php (3)

30-30: Use allowed_classes option with unserialize for safer deserialization.

Using unserialize() without restrictions can be a security risk if the cache is ever compromised. Specify the expected class to prevent object injection attacks.

-                        return unserialize($cached);
+                        return unserialize($cached, ['allowed_classes' => [Schema::class]]);

17-34: Consider extracting cache retrieval logic to reduce duplication.

The cache retrieval pattern (check mtime, get cached value, log hit) is duplicated between asArray() and asJson(). This violates the DRY principle and makes maintenance harder.

Consider extracting a private helper method:

private static function getFromCache(string $cacheKey, string $filePath, string $type): mixed
{
    if (!class_exists('\App') || !isset(\App::$cache) || !\App::$cache || !file_exists($filePath)) {
        return null;
    }
    
    $cacheMtime = \App::$cache->get($cacheKey . '_mtime');
    if ($cacheMtime === null || $cacheMtime < filemtime($filePath)) {
        return null;
    }
    
    $cached = \App::$cache->get($cacheKey);
    if ($cached !== null && class_exists('\App') && isset(\App::$log) && \App::$log) {
        \App::$log->debug('Schema cache hit', ['schema' => $cacheKey, 'type' => $type]);
    }
    return $cached;
}

Also applies to: 85-102


58-60: Store filemtime result to avoid redundant syscalls on cache miss.

When the cache is missed, filemtime() is called again at line 60 (and similarly at line 110 in asJson). Consider storing the mtime value earlier for reuse.

+        $fileMtime = file_exists($fullPath) ? filemtime($fullPath) : null;
+
         // Try to get from cache
         if (class_exists('\App') && isset(\App::$cache) && \App::$cache && file_exists($fullPath)) {
             $cacheMtime = \App::$cache->get($cacheKey . '_mtime');
             if ($cacheMtime !== null) {
-                $fileMtime = filemtime($fullPath);
                 if ($cacheMtime >= $fileMtime) {
                     // ...
                 }
             }
         }
         // ... later ...
-            \App::$cache->set($cacheKey . '_mtime', filemtime($fullPath));
+            \App::$cache->set($cacheKey . '_mtime', $fileMtime);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e29a17 and d682dfd.

⛔ Files ignored due to path filters (1)
  • zmsentities/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • zmsentities/composer.json (1 hunks)
  • zmsentities/src/Zmsentities/Schema/Loader.php (3 hunks)
  • zmsentities/src/Zmsentities/Schema/Validator.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmsentities/src/Zmsentities/Schema/Validator.php
  • zmsentities/src/Zmsentities/Schema/Loader.php
  • zmsentities/composer.json
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmsentities/src/Zmsentities/Schema/Validator.php
  • zmsentities/src/Zmsentities/Schema/Loader.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsdb, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsclient, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsdldb, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsentities, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsstatistic, 8.3)
  • GitHub Check: call-zmsautomation-tests / zmsapiautomation
  • GitHub Check: call-php-unit-tests / zmsapi-test
  • GitHub Check: call-php-unit-tests / zmsdb-test
🔇 Additional comments (1)
zmsentities/src/Zmsentities/Schema/Validator.php (1)

53-59: LGTM!

The integration with Loader::asJson() is clean and maintains the existing schema registration behavior while enabling cache-backed loading. The variable rename to $schemaFilename improves clarity.

Copy link
Contributor

@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: 4

♻️ Duplicate comments (3)
zmsentities/src/Zmsentities/Schema/Loader.php (3)

30-35: Duplicate: INFO log level already flagged in past review.

As noted in a previous review comment, cache hit/set events should use DEBUG level instead of INFO to avoid excessive log noise.


48-53: Duplicate: INFO log level already flagged in past review.

As noted in a previous review comment, cache set events should use DEBUG level instead of INFO to avoid excessive log noise.


120-121: Duplicate: file_get_contents() error handling already flagged in past review.

A previous review comment already identified that file_get_contents() can return false on failure, which would then be cached and cause downstream errors.

🧹 Nitpick comments (1)
zmsentities/src/Zmsentities/Schema/Loader.php (1)

9-9: Add return type declarations for better type safety.

All four methods in this file lack return type declarations. Adding them would improve IDE support, catch potential bugs earlier, and make the API clearer.

-    private static function getCachedSchema(string $cacheKey, string $fullPath, string $schemaFilename, string $type)
+    private static function getCachedSchema(string $cacheKey, string $fullPath, string $schemaFilename, string $type): ?string

-    private static function setCachedSchema(string $cacheKey, string $fullPath, string $schemaFilename, string $type, $data): void
+    private static function setCachedSchema(string $cacheKey, string $fullPath, string $schemaFilename, string $type, string $data): void

-    public static function asArray($schemaFilename)
+    public static function asArray(string $schemaFilename): Schema

-    public static function asJson($schemaFilename)
+    public static function asJson(string $schemaFilename): string

Also applies to: 40-40, 76-76, 102-102

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d682dfd and 6922936.

📒 Files selected for processing (1)
  • zmsentities/src/Zmsentities/Schema/Loader.php (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmsentities/src/Zmsentities/Schema/Loader.php
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmsentities/src/Zmsentities/Schema/Loader.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: build (zmscitizenview)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: call-php-unit-tests / module-test (zmsmessaging, 8.3)
  • GitHub Check: call-php-unit-tests / module-test (zmsadmin, 8.3)
  • GitHub Check: call-zmsautomation-tests / zmsapiautomation
  • GitHub Check: call-php-unit-tests / zmsdb-test
  • GitHub Check: call-php-unit-tests / zmsapi-test
🔇 Additional comments (1)
zmsentities/src/Zmsentities/Schema/Loader.php (1)

56-74: LGTM!

The JSON parsing logic includes comprehensive error handling with clear, specific error messages for different JSON error types.

- Change log level from info to debug for cache hits and sets
- Prevents test failures by avoiding unexpected log output
- Debug logs still available when DEBUGLEVEL is set to DEBUG
- Check if file_get_contents() returns false before caching
- Throw SchemaMissingJsonFile exception with clear error message
- Prevents caching false values that would cause json_decode errors
Copy link
Contributor

@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: 2

🧹 Nitpick comments (1)
zmsentities/src/Zmsentities/Schema/Loader.php (1)

9-127: Good caching implementation with proper mtime-based freshness checks.

The overall caching strategy is well-designed:

  • Separate cache keys for JSON and parsed schemas
  • mtime-based cache invalidation ensures freshness
  • Proper fallback when cache is unavailable
  • Debug-level logging is appropriate for cache operations (addresses previous feedback)

Consider adding type declarations to improve code clarity and catch type errors earlier:

private static function getCachedSchema(
    string $cacheKey, 
    string $fullPath, 
    string $schemaFilename, 
    string $type
): ?string { /* ... */ }

private static function setCachedSchema(
    string $cacheKey, 
    string $fullPath, 
    string $schemaFilename, 
    string $type, 
    string $data
): void { /* ... */ }

public static function asArray(string $schemaFilename): Schema { /* ... */ }

public static function asJson(string $schemaFilename): string { /* ... */ }

As per coding guidelines, proper type hints improve maintainability and readability.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6922936 and 330a648.

📒 Files selected for processing (1)
  • zmsentities/src/Zmsentities/Schema/Loader.php (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmsentities/src/Zmsentities/Schema/Loader.php
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmsentities/src/Zmsentities/Schema/Loader.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: call-php-unit-tests / zmsapi-test
  • GitHub Check: call-zmsautomation-tests / zmsapiautomation
  • GitHub Check: call-php-unit-tests / zmsdb-test

- Change symfony/cache from ^6.0 to ^5.4
- Matches existing symfony/translation and symfony/twig-bridge versions
- Prevents potential dependency conflicts and runtime issues
- Check cache first before validating file existence
- Allows cache to be checked even if file is temporarily unavailable
- Still validates file exists before returning cached data (schema files should exist)
- File existence check remains in setCachedSchema for write operations
- Check if filemtime() returns false before comparing with cached mtime
- Prevents incorrect cache invalidation when file access fails
- Also handle filemtime() failure in setCachedSchema to avoid caching false values
- Store JSON string instead of serialized Schema object in cache
- Reconstruct Schema object from JSON on cache retrieval
- Eliminates security risk of arbitrary code execution via unserialize()
- JSON is safer than PHP serialization for cached data
…tor bug

- Add absolute path handling to asArray() to match asJson() behavior
- Fix double-separator bug when absolute paths are provided
- Ensures consistent path resolution across both methods
- Extract isCacheAvailable() helper method
- Extract validateCacheMtime() helper method
- Extract logCacheHit() helper method
- Reduces NPath complexity from 512 to below threshold
Copy link
Contributor

@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: 0

🧹 Nitpick comments (1)
zmsentities/src/Zmsentities/Schema/Loader.php (1)

22-24: Reconsider: Redundant file existence check may hinder caching effectiveness.

This explicit file_exists($fullPath) check is redundant because filemtime() on line 26 already returns false when the file doesn't exist, which is properly handled on lines 27-29. The explicit check prevents returning cached data when the source file has been deleted, which may defeat the caching purpose in scenarios where cached schemas should remain available even after file removal.

Per the previous review discussion, the filemtime() check alone provides sufficient validation while allowing the cache to work independently of current file presence.

Consider removing the redundant check:

-    // Validate file exists and compare modification times
-    if (!file_exists($fullPath)) {
-        return null;
-    }
-
     $fileMtime = filemtime($fullPath);
     if ($fileMtime === false) {
         return null;
     }

The filemtime === false check already handles missing files gracefully while allowing valid cached data to be served when appropriate.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 330a648 and 149af44.

⛔ Files ignored due to path filters (1)
  • zmsentities/composer.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • zmsentities/composer.json (1 hunks)
  • zmsentities/src/Zmsentities/Schema/Loader.php (3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*

⚙️ CodeRabbit configuration file

**/*: Apply the following Clean Code guidelines to all files, as summarized by wojteklu's Clean Code gist:

Code is clean if it can be understood easily – by everyone on the team. Clean code can be read and enhanced by a developer other than its original author. With understandability comes readability, changeability, extensibility and maintainability.

General rules

  1. Follow standard conventions.
  2. Keep it simple stupid. Simpler is always better. Reduce complexity as much as possible.
  3. Boy scout rule. Leave the campground cleaner than you found it.
  4. Always find root cause. Always look for the root cause of a problem.

Design rules

  1. Keep configurable data at high levels.
  2. Prefer polymorphism to if/else or switch/case.
  3. Separate multi-threading code.
  4. Prevent over-configurability.
  5. Use dependency injection.
  6. Follow Law of Demeter. A class should know only its direct dependencies.

Understandability tips

  1. Be consistent. If you do something a certain way, do all similar things in the same way.
  2. Use explanatory variables.
  3. Encapsulate boundary conditions. Boundary conditions are hard to keep track of. Put the processing for them in one place.
  4. Prefer dedicated value objects to primitive type.
  5. Avoid logical dependency. Don't write methods which works correctly depending on something else in the same class.
  6. Avoid negative conditionals.

Names rules

  1. Choose descriptive and unambiguous names.
  2. Make meaningful distinction.
  3. Use pronounceable names.
  4. Use searchable names.
  5. Replace magic numbers with named constants.
  6. Avoid encodings. Don't append prefixes or type information.

Functions rules

  1. Small.
  2. Do one thing.
  3. Use descriptive names.
  4. Prefer fewer arguments.
  5. Have no side effects.
  6. Don't use flag arguments. Split method into several independent methods that can b...

Files:

  • zmsentities/composer.json
  • zmsentities/src/Zmsentities/Schema/Loader.php
**/*.php

⚙️ CodeRabbit configuration file

**/*.php: Flag any usage of error_log() as it should be replaced with proper Monolog logging mechanisms provided by zmsslim which should be setup in the App/Application of each module:

  1. For error handling: Use the proper Monolog logging framework with error levels
  2. For application info logs: Use the proper Monolog logging framework with info levels
  3. For debugging: Use a dedicated debug logger or remove debug statements
  4. For CLI output: Use a CLI output handler or symfony/console
  5. The application log levels are as follows DEBUG, INFO, NOTICE, WARNING, ERROR, CRITICAL, ALERT, and EMERGENCY

Example replacement:

// Instead of:
error_log("Import failed - " . $e->getMessage());

// Use:
$log->error("Import failed", ['error' => $e->getMessage()]);

Flag specific logging violations:

  1. error_log(), var_dump(), print_r(), die(), exit() usage (except proper error logging in catch blocks)
  2. Any debug output that should use proper Monolog logging
  3. Debug constants like DEBUG = true
  4. Debug logging that should be removed in production
  5. Commented debug code that should be cleaned up

Example replacements:

// Instead of:
error_log("Error occurred");
var_dump($data);
die('debug point');

// Use:
$log->error("Error occurred", ['context' => 'processing']);
$log->debug('Data dump', ['data' => $data]);
// Remove die() statements entirely

Exception handling should use proper logging:

// Instead of:
try {
    $result = $this->process();
} catch (Exception $e) {
    error_log("Processing failed: " . $e->getMessage());
}

// Use:
try {
    $result = $this->process();
} catch (Exception $e) {
    $log->error("Processing failed", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
```...

Files:

  • zmsentities/src/Zmsentities/Schema/Loader.php
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
  • GitHub Check: call-zmsautomation-tests / zmsapiautomation
  • GitHub Check: call-php-code-quality / module-code-quality (zmsslim, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsstatistic, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsdb, 8.3)
  • GitHub Check: call-php-code-quality / module-code-quality (zmsapi, 8.3)
  • GitHub Check: call-php-unit-tests / module-test (zmsslim, 8.3)
  • GitHub Check: call-php-unit-tests / module-test (zmsstatistic, 8.3)
  • GitHub Check: call-php-unit-tests / module-test (zmscitizenapi, 8.3)
  • GitHub Check: call-php-unit-tests / zmsclient-test
  • GitHub Check: call-php-unit-tests / zmsdb-test
  • GitHub Check: call-php-unit-tests / zmsapi-test
🔇 Additional comments (8)
zmsentities/composer.json (1)

24-25: LGTM! Cache dependencies properly aligned.

The addition of symfony/cache and psr/simple-cache at version ^5.4 and ^3.0 respectively properly supports the PSR-16 caching infrastructure implemented in Loader.php. All Symfony packages maintain consistent versioning at ^5.4.

zmsentities/src/Zmsentities/Schema/Loader.php (7)

9-12: LGTM! Clean cache availability check.

The defensive checking pattern (class existence → isset → truthiness) properly guards against missing cache infrastructure.


37-45: LGTM! Appropriate debug logging.

Cache hit logging correctly uses DEBUG level for routine operational events and includes useful context (schema filename and type).


47-64: LGTM! Clean cache retrieval logic.

The method properly delegates to helpers (isCacheAvailable, validateCacheMtime, logCacheHit) and uses clear early-return patterns.


66-83: LGTM! Robust cache storage with proper error handling.

The method correctly:

  • Validates file existence before caching (appropriate for cache writes)
  • Handles filemtime() failure (lines 73-76)
  • Logs at DEBUG level
  • All past review issues properly addressed

85-103: LGTM! Comprehensive JSON parse error handling.

The method provides detailed error messages for various JSON parsing failures and properly includes the schema filename for debugging. Good refactoring of existing logic.


105-140: LGTM! Secure cache-backed schema loading.

The refactored method properly:

  • Handles absolute paths (lines 111-116)
  • Reconstructs Schema safely from cached JSON instead of unserialize() (lines 122-126)
  • Delegates JSON parsing to the helper
  • Caches JSON strings for safety

All past security and correctness issues properly addressed.


142-177: LGTM! Robust JSON loading with proper error handling.

The refactored method properly:

  • Handles absolute paths without double-separator issues (lines 149-154)
  • Validates file_get_contents() failure with clear exception (lines 167-171)
  • Integrates caching seamlessly

All past review issues properly addressed.

@ThomasAFink ThomasAFink added php Pull requests that update Php code caching All caching file or in memory performance Improving performance labels Dec 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

caching All caching file or in memory performance Improving performance php Pull requests that update Php code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants