Add camelCase dynamic finders and counters#16
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0dea91ba31
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| protected static function camelToSnake($fieldname) | ||
| { | ||
| $snake = preg_replace('/(?<!^)[A-Z]/', '_$0', $fieldname); | ||
| return strtolower($snake ?? $fieldname); |
There was a problem hiding this comment.
Handle acronym segments when converting camelCase to snake_case
The new camelToSnake helper splits before every capital letter, so camelCase names with acronym runs (e.g., findByProductID or findByURLValue) become product_i_d/u_r_l_value. resolveFieldName then fails to match the actual snake_case column (e.g., product_id or url_value) and falls back to the original productID, which is quoted and queried as a non-existent column. This will throw SQL errors or return no rows whenever a model has acronym-style column names and users rely on the new camelCase dynamic finders. Consider a regex that collapses consecutive capitals into a single word boundary.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR extends the model’s dynamic finder/counter API to support CamelCase method names and more flexible field-name resolution, and adds corresponding annotations, tests, and docs. It also refactors dynamic count logic to reuse shared helpers.
Changes:
- Add CamelCase dynamic finder/counter support in
Model::__callStatic(e.g.,findByName,findOneByName,firstByName,lastByName,countByName) and introduceresolveFieldName,camelToSnake, andcountByFieldhelpers to resolve method segments to actual column names, including snake_case. - Update the
App\Model\Categorytest model annotations and addCategoryTest::testDynamicFindersCamelCaseto exercise the new CamelCase dynamic methods. - Extend the README dynamic finder section with documentation and examples for CamelCase alternatives.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/Model/Model.php |
Adds CamelCase dynamic method handling plus shared helpers for resolving field names and counting by field, centralizing and extending dynamic finder behavior. |
tests/Model/CategoryTest.php |
Introduces a new test that verifies the CamelCase dynamic finders and counter for the name field using the Category model. |
test-src/Model/Category.php |
Updates model docblock annotations to declare the new CamelCase dynamic finder/counter methods for static analysis and IDE support. |
README.md |
Documents CamelCase alternatives for dynamic finders, showing example usage alongside the existing underscore-based methods. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| protected static function resolveFieldName($fieldname) | ||
| { | ||
| $fieldnames = static::getFieldnames(); | ||
| if (in_array($fieldname, $fieldnames, true)) { | ||
| return $fieldname; | ||
| } | ||
| foreach ($fieldnames as $field) { | ||
| if (strcasecmp($field, $fieldname) === 0) { | ||
| return $field; | ||
| } | ||
| } | ||
| $snake = static::camelToSnake($fieldname); | ||
| if (in_array($snake, $fieldnames, true)) { | ||
| return $snake; | ||
| } | ||
| foreach ($fieldnames as $field) { | ||
| if (strcasecmp($field, $snake) === 0) { | ||
| return $field; | ||
| } | ||
| } | ||
| return $fieldname; | ||
| } | ||
|
|
||
| /** | ||
| * Convert CamelCase or mixedCase to snake_case. | ||
| * | ||
| * @param string $fieldname | ||
| * | ||
| * @return string | ||
| */ | ||
| protected static function camelToSnake($fieldname) | ||
| { | ||
| $snake = preg_replace('/(?<!^)[A-Z]/', '_$0', $fieldname); | ||
| return strtolower($snake ?? $fieldname); | ||
| } |
There was a problem hiding this comment.
The new resolveFieldName/camelToSnake logic that maps CamelCase method segments to snake_case column names (e.g. findByCreatedAt -> created_at) is not covered by tests; the current testDynamicFindersCamelCase only exercises simple case-insensitive matching for name and never hits the camel-to-snake path. Please add test coverage for at least one snake_case column (such as created_at) using the new CamelCase dynamic methods so this behavior is verified and guarded against regressions.
Summary
Testing