Skip to content

New early return sniff#2828

Merged
Crabcyborg merged 8 commits into
masterfrom
new_early_return_sniff
Jan 16, 2026
Merged

New early return sniff#2828
Crabcyborg merged 8 commits into
masterfrom
new_early_return_sniff

Conversation

@Crabcyborg
Copy link
Copy Markdown
Contributor

@Crabcyborg Crabcyborg commented Jan 16, 2026

Summary by CodeRabbit

  • Refactor

    • Simplified control flow and added early-return patterns across form processing, field validation, email/SMTP handling, entry formatting, and query generation to improve reliability and maintainability.
    • Adjusted form deletion and migration flows to avoid unintended side effects on failure.
  • Chores

    • Added a new code-analysis rule to help enforce early-return patterns during development.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 16, 2026

Warning

Rate limit exceeded

@Crabcyborg has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 21 minutes and 1 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 43934d6 and 5df9194.

📒 Files selected for processing (2)
  • classes/controllers/FrmSMTPController.php
  • stripe/controllers/FrmStrpLiteEventsController.php
📝 Walkthrough

Walkthrough

This PR applies guard-clause/early-return refactors across multiple helpers, models, controllers and field classes, and adds a new PHP_CodeSniffer sniff (FlipIfToEarlyReturnVariableSniff) with a ruleset entry to detect and auto-fix if->early-return variable patterns.

Changes

Cohort / File(s) Summary
Core Helpers
classes/helpers/FrmAppHelper.php, classes/helpers/FrmEmailSummaryHelper.php, classes/helpers/FrmEntriesHelper.php, classes/helpers/FrmFormsHelper.php, classes/helpers/FrmXMLHelper.php
Added early-return guards and inverted conditionals in param/key handling, option loading, POST detection, link formatting, and XML placeholder migration; control flow simplified with earlier exits.
Model Core
classes/models/FrmDb.php, classes/models/FrmEntryFormatter.php, classes/models/FrmForm.php, classes/models/FrmFormAction.php, classes/models/FrmFormApi.php
Early returns added to query construction, HTML stripping, form deletion, migration update path, and API error extraction; WHERE assembly, deletion post-processing, and error extraction reordered.
Field Models
classes/models/fields/FrmFieldCaptcha.php, classes/models/fields/FrmFieldGdpr.php, classes/models/fields/FrmFieldType.php, classes/models/fields/FrmFieldUrl.php
Validation and display methods now short-circuit non-applicable cases earlier (captcha/gdpr validation, select attributes, display value, URL HTML rendering).
SMTP Controller
classes/controllers/FrmSMTPController.php
get_phpmailer() simplified to return existing PHPMailer early; initialization path preserved.
Stripe Integration
stripe/controllers/FrmStrpLiteEventsController.php, stripe/helpers/FrmStrpLiteSubscriptionHelper.php
is_partial_refund() and get_plan_for_action() refactored to short-circuit on non-refunded status or existing plan_id respectively.
PHPCS Sniff
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/FlipIfToEarlyReturnVariableSniff.php
New sniff class (adds public $minStatements, register(), process()) detecting top-level ifs that assign a variable returned later; emits fixable suggestions and auto-fix to flip to early-return.
PHPCS Ruleset
phpcs-sniffs/Formidable/ruleset.xml
Registers new Formidable.CodeAnalysis.FlipIfToEarlyReturnVariable rule in project ruleset.

Sequence Diagram(s)

(omitted — changes are refactors and a static analysis addition that do not introduce a multi-component runtime sequence needing visualization)

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code, found nested plight,

I nudged the ifs to take the flight,
Early returns now clear the way,
A sniff sniffs out the tangled clay,
Hooray — less nest, more springtime play!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'New early return sniff' accurately describes the primary change: introducing a new PHP_CodeSniffer sniff (FlipIfToEarlyReturnVariableSniff) that detects and suggests refactoring opportunities for early returns.
Docstring Coverage ✅ Passed Docstring coverage is 94.59% which is sufficient. The required threshold is 80.00%.

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


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
Copy Markdown
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

🤖 Fix all issues with AI agents
In `@classes/helpers/FrmEmailSummaryHelper.php`:
- Around line 78-83: In FrmEmailSummaryHelper, remove the unreachable dead
return statement (the final "return $options;") that comes after
"self::save_options($default_options); return $default_options;"; locate the
block where self::save_options, $default_options and $options are used and
delete the trailing return $options; so the method returns only $default_options
and has no unreachable code.

In `@classes/helpers/FrmFormsHelper.php`:
- Around line 1346-1368: The current logic in FrmFormsHelper::delete_trash_links
(handling $link_details in the code block building $link) uses an elseif so when
$link_details['data'] exists the confirm onclick is skipped; change the flow to
allow both data attributes and the confirm fallback to be added: replace the
elseif with a separate if that appends the onclick confirm handler when
isset($link_details['confirm']) in addition to the existing loop that adds
data-* attributes from $link_details['data'], ensuring you keep escaping via
esc_attr() and esc_url() and still build $link and $label as before (references:
$link_details, $link, $length).

In `@classes/models/FrmEntryFormatter.php`:
- Around line 971-973: Fix the syntax error in FrmEntryFormatter where the
condition reads "$this - <= is_plain_text": replace this malformed expression
with a proper property check using the object operator and negation (i.e., check
that is_plain_text is false) so the early-return that returns $value executes
when ! $this->is_plain_text; update the condition in the method containing that
return to use $this->is_plain_text with correct negation and object operator.

In `@classes/models/FrmForm.php`:
- Around line 730-746: The current check treats $query_results falsy and returns
early, which incorrectly skips cleanup when $wpdb->query() returns 0 (no rows
deleted); change the guard in the delete flow to only return on strict false
(error) instead of falsy, so that
FrmFormActionsController::get_form_actions('email')->destroy($id, 'all'),
self::clear_form_cache(), and the do_action('frm_destroy_form', $id) /
do_action('frm_destroy_form_' . $id) calls still run when $query_results === 0
but not when $query_results === false.
🧹 Nitpick comments (8)
classes/models/fields/FrmFieldUrl.php (1)

110-113: Simplify return value per Rector suggestion.

The assignment to $value before returning is unnecessary. As flagged by the pipeline, this can be simplified by returning $images directly. Also removes the extra blank lines.

♻️ Suggested fix
 		}
 
-		$value = $images;
-
-
-		return $value;
+		return $images;
 	}
classes/models/fields/FrmFieldType.php (2)

1468-1481: LGTM! Clean early-return refactor.

The flip from nested if (!$readonly) to an early return for the readonly case improves readability while preserving the original behavior.

Minor nit: Lines 1479-1480 have two consecutive blank lines before the return statement, which could be reduced to one for consistency.

🧹 Optional: Remove extra blank line
 		$select_atts['name'] = $values['field_name'];
 		$select_atts['id']   = $values['html_id'];
-
 
 		return $select_atts;

1716-1728: LGTM! Early-return guard correctly applied.

The refactoring correctly returns non-array values early, then handles array processing (show attribute lookup or implode with separator). Logic is preserved.

Same minor nit as above: Lines 1726-1727 have two consecutive blank lines that could be consolidated.

🧹 Optional: Remove extra blank line
 		$sep   = $atts['sep'] ?? ', ';
 		$value = FrmAppHelper::safe_implode( $sep, $value );
 	}
-
 
 	return $value;
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/FlipIfToEarlyReturnVariableSniff.php (1)

52-54: Consider adding T_CLOSURE to the registered tokens.

The sniff currently only triggers on T_FUNCTION. If the early-return pattern should also apply to closures/anonymous functions, consider:

 public function register() {
-    return array( T_FUNCTION );
+    return array( T_FUNCTION, T_CLOSURE );
 }

If this is intentional (e.g., closures are typically short), this comment can be ignored.

classes/models/FrmEntryFormatter.php (1)

979-986: Redundant condition after early return fix.

Once line 971 is fixed to if ( ! $this->is_plain_text ), the condition on line 979 becomes redundant since:

  1. $this->is_plain_text is guaranteed to be true (we returned early if not)
  2. ! is_array( $value ) is guaranteed true (the preceding if block handles arrays)
♻️ Suggested simplification
     if ( is_array( $value ) ) {
         foreach ( $value as $key => $single_value ) {
             $value[ $key ] = $this->strip_html( $single_value );
         }
-    } elseif ( $this->is_plain_text && ! is_array( $value ) ) {
+    } else {
         if ( str_contains( $value, '<img' ) ) {
             $value = str_replace( array( '<img', 'src=', '/>', '"' ), '', $value );
             $value = trim( $value );
         }
 
         $value = strip_tags( $value );
     }
-
 
     return $value;
classes/models/fields/FrmFieldGdpr.php (1)

182-184: Logic is correct, but the double negation reduces readability.

The condition ! ( ! $errors && ! FrmFieldGdprHelper::hide_gdpr_field() ) is logically equivalent to $errors || FrmFieldGdprHelper::hide_gdpr_field() via De Morgan's law. Consider simplifying for clarity:

♻️ Optional: Improve readability using De Morgan's simplification
-    if ( ! ( ! $errors && ! FrmFieldGdprHelper::hide_gdpr_field() ) ) {
+    if ( $errors || FrmFieldGdprHelper::hide_gdpr_field() ) {
         return $errors;
     }
classes/helpers/FrmXMLHelper.php (1)

775-798: LGTM - Early return correctly preserves the conditional logic.

The guard clause properly handles the case where $type !== 'default_blank' or $options is not an array, returning $changes early. The remaining logic for processing dropdown placeholder options is unchanged.

Note: Line 798 has an orphaned // end if comment that's no longer relevant after the refactor.

🧹 Remove orphaned comment
 	$changes['options'] = $options;
-	// end if

 	return $changes;
classes/controllers/FrmSMTPController.php (1)

412-424: Consider simplifying the double-negated condition.

The current condition ! ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'PHPMailer' ) ) applies De Morgan's law but leaves unnecessary negations. This can be simplified for readability.

♻️ Simplify condition
-		if ( ! ( ! is_object( $phpmailer ) || ! is_a( $phpmailer, 'PHPMailer' ) ) ) {
+		if ( is_object( $phpmailer ) && $phpmailer instanceof PHPMailer ) {
 			return $phpmailer;
 		}

Note: Using instanceof is preferred over is_a() for type checking in PHP as it's more performant and idiomatic.

Comment thread classes/helpers/FrmEmailSummaryHelper.php Outdated
Comment thread classes/helpers/FrmFormsHelper.php Outdated
Comment thread classes/models/FrmEntryFormatter.php Outdated
Comment thread classes/models/FrmForm.php
@Crabcyborg
Copy link
Copy Markdown
Contributor Author

@coderabbitai re-review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 16, 2026

@Crabcyborg: I'll re-review the changes in this PR.

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

Copy link
Copy Markdown
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

🤖 Fix all issues with AI agents
In `@classes/models/fields/FrmFieldCaptcha.php`:
- Around line 320-332: The current logic in FrmFieldCaptcha.php returns success
when $response['success'] is missing or true; change it to fail closed by only
treating validation as passed when the success key is present and truthy.
Replace the early-return condition with a check that returns $errors only when
isset($response['success']) && $response['success'] is true (otherwise proceed
to set the error entry in $errors['field' . $args['id']]); update the block
around $response, $errors, and the invalid message handling in the
FrmFieldCaptcha class accordingly.

In `@classes/models/fields/FrmFieldUrl.php`:
- Line 106: Replace the call to strip_tags when appending the URL with proper
HTML escaping: where FrmFieldUrl builds $images and currently does $images .=
strip_tags($url) (when $atts['html'] is true), use esc_html($url) instead so
special characters are escaped for safe HTML output; update the code path in
FrmFieldUrl that handles $atts['html'] to call esc_html on $url before
concatenation.

In
`@phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/FlipIfToEarlyReturnVariableSniff.php`:
- Around line 485-503: The negation fallback in FlipIfToEarlyReturnVariableSniff
returns '! ' . $condition without parentheses which breaks operator precedence
and flipComparisonOperator() may flip operators inside string literals; update
the fallback to return '! (' . $condition . ')' (matching the compound branch)
and, before calling flipComparisonOperator($condition), add a guard that rejects
conditions containing single or double quotes or escaped quotes (e.g. preg_match
on /['"]/) so flipComparisonOperator is skipped when $condition contains string
literals or patterns.
- Around line 269-281: The hasElseOrElseif method is skipping only whitespace
when searching after the if scope closer, so comments between the closing brace
and an else/elseif aren't skipped; update the phpcsFile->findNext call in
hasElseOrElseif to skip both T_WHITESPACE and comment tokens (e.g. T_COMMENT and
T_DOC_COMMENT) by passing an array of those token constants with the $exclude
flag set to true when searching from $scopeCloser + 1, then keep the existing
check that uses $next and returns in_array($tokens[$next]['code'], array(T_ELSE,
T_ELSEIF), true).
♻️ Duplicate comments (1)
classes/helpers/FrmFormsHelper.php (1)

1352-1358: The elseif concern remains unaddressed.

As noted in a previous review, using elseif here means the confirm onclick handler is skipped whenever data attributes exist. Looking at delete_trash_links() (line 1419-1430), the 'delete' array defines both data and confirm keys, so the confirm fallback is currently being dropped.

🧹 Nitpick comments (1)
phpcs-sniffs/Formidable/Sniffs/CodeAnalysis/FlipIfToEarlyReturnVariableSniff.php (1)

229-233: Unused parameters flagged by PHPMD.
$phpcsFile isn’t used in findPrecedingIf, countStatementsInScope, or getConditionString; consider removing it from signatures/call sites to quiet the linter.

Also applies to: 293-295, 321-323

Comment thread classes/models/fields/FrmFieldCaptcha.php
Comment thread classes/models/fields/FrmFieldUrl.php
@Crabcyborg Crabcyborg merged commit 8ee64a3 into master Jan 16, 2026
16 checks passed
@Crabcyborg Crabcyborg deleted the new_early_return_sniff branch January 16, 2026 23:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant