@@ -35,7 +35,7 @@ echo $category->created_at;
3535echo $category->updated_at;
3636```
3737
38- ` save() ` inserts when the primary key is empty and updates when the primary key is present.
38+ ` save() ` inserts when the primary key is ` null ` and updates when the primary key is present.
3939
4040## Load a record by primary key
4141
@@ -93,17 +93,7 @@ $count = Category::count();
9393
9494## Dynamic finders
9595
96- Snake_case methods:
97-
98- ``` php
99- $all = Category::find_by_name('Fiction');
100- $one = Category::findOne_by_name('Fiction');
101- $first = Category::first_by_name(['Fiction', 'Fantasy']);
102- $last = Category::last_by_name(['Fiction', 'Fantasy']);
103- $count = Category::count_by_name('Fiction');
104- ```
105-
106- CamelCase alternatives:
96+ Preferred camelCase methods:
10797
10898``` php
10999$all = Category::findByName('Fiction');
@@ -113,6 +103,30 @@ $last = Category::lastByName(['Fiction', 'Fantasy']);
113103$count = Category::countByName('Fiction');
114104```
115105
106+ Legacy snake_case dynamic methods still work during the transition, but they are deprecated and should be migrated.
107+
108+ ## Focused query helpers
109+
110+ Check existence:
111+
112+ ``` php
113+ $hasCategories = Category::exists();
114+ $hasFiction = Category::existsWhere('name = ?', ['Fiction']);
115+ ```
116+
117+ Fetch ordered results:
118+
119+ ``` php
120+ $alphabetical = Category::fetchAllWhereOrderedBy('name', 'ASC');
121+ $latest = Category::fetchOneWhereOrderedBy('id', 'DESC');
122+ ```
123+
124+ Pluck one column:
125+
126+ ``` php
127+ $names = Category::pluck('name', '', [], 'name', 'ASC', 10);
128+ ```
129+
116130## Custom WHERE clauses
117131
118132Fetch a single matching record:
@@ -181,21 +195,43 @@ $rows = $statement->fetchAll(PDO::FETCH_ASSOC);
181195
182196## Validation
183197
184- Override ` validate() ` to enforce model rules before insert and update:
198+ Use instance-aware hooks to enforce model rules before insert and update:
185199
186200``` php
187201class Category extends Freshsauce\Model\Model
188202{
189203 protected static $_tableName = 'categories';
190204
191- public static function validate()
205+ protected function validateForSave(): void
192206 {
193- return true;
207+ if (trim((string) $this->name) === '') {
208+ throw new RuntimeException('Name is required');
209+ }
194210 }
195211}
196212```
197213
198- Throw an exception from ` validate() ` whenever your application-specific rule fails, and the write will be aborted before insert or update.
214+ Override ` validateForInsert() ` or ` validateForUpdate() ` when the rules are operation-specific.
215+
216+ The legacy static ` validate() ` method remains supported for backward compatibility.
217+
218+ ## Strict field mode
219+
220+ Enable strict field mode when you want unknown assignments to fail immediately instead of being silently ignored on persistence:
221+
222+ ``` php
223+ class Category extends Freshsauce\Model\Model
224+ {
225+ protected static $_tableName = 'categories';
226+ protected static bool $_strict_fields = true;
227+ }
228+ ```
229+
230+ Or enable it temporarily:
231+
232+ ``` php
233+ Category::useStrictFields(true);
234+ ```
199235
200236## MySQL example connection
201237
0 commit comments