Skip to content

feat: add Query Builder likeAny helpers#10261

Open
memleakd wants to merge 1 commit into
codeigniter4:4.8from
memleakd:feat/query-builder-like-any
Open

feat: add Query Builder likeAny helpers#10261
memleakd wants to merge 1 commit into
codeigniter4:4.8from
memleakd:feat/query-builder-like-any

Conversation

@memleakd
Copy link
Copy Markdown
Contributor

Description

This PR proposes adding likeAny() and orLikeAny() to Query Builder.

The goal is to make a very common search pattern easier to write: search one value across a few columns, while keeping those LIKE conditions grouped safely.

$builder->where('active', 1)->likeAny(['title', 'body', 'summary'], $search);

Instead of writing the group manually, this produces the expected shape:

WHERE active = 1
AND (
    title LIKE '%term%'
    OR body LIKE '%term%'
    OR summary LIKE '%term%'
)

This keeps the existing like() behavior unchanged. Passing an associative array to like() still creates multiple LIKE clauses joined with AND; likeAny() is only for the "same value across any of these fields" case.

Internally this reuses the existing LIKE handling, so binds, escaping, wildcard placement, RawSql, and case-insensitive search behave the same way as like().

Tests cover grouped SQL generation, binds, invalid field lists, RawSql, case-insensitive search, and live database behavior.

Checklist:

  • Securely signed commits
  • Component(s) with PHPDoc blocks, only if necessary or adds value (without duplication)
  • Unit testing, with >80% coverage
  • User guide updated
  • Conforms to style guide

- add likeAny() and orLikeAny() for grouped OR LIKE searches
- reuse existing LIKE handling for binds, escaping, RawSql, and insensitive search
- document usage and add builder/live coverage

Signed-off-by: memleakd <121398829+memleakd@users.noreply.github.com>
@github-actions github-actions Bot added the 4.8 PRs that target the `4.8` branch. label May 31, 2026

if (! is_string($field) || trim($field) === '') {
throw new InvalidArgumentException(sprintf('%s() expects $fields to contain only non-empty strings or RawSql instances', $caller));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
}
}
if (! preg_match('/^[A-Za-z0-9_\.]+$/', $field)) {
throw new InvalidArgumentException(sprintf('Invalid field name "%s". Only alphanumeric characters, underscore, and dot are allowed.', $field));
}

I suggested the strict field-name check because these values are used as SQL identifiers, not regular data values, so is_string() alone doesn’t really guarantee they’re safe.

Using a small allowlist here feels like a nice extra guardrail before the query is built.

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks for taking a look.

I don't think we should add this validation here. It would make this method more restrictive than the rest of Query Builder, and identifier protection should stay in the existing escaping/compiler flow.

I agree with the safety concern though, so I think a docs note about not passing user input directly as field names would be a better fit.

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

Labels

4.8 PRs that target the `4.8` branch.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants