# mfBaseModelV2 Modern PHP 8+ base model with typed properties and automatic journaling. ## Basic Usage ```php class ADBNetzgebiet extends mfBaseModelV2 { protected static string $__tableName = 'Netzgebiet'; protected static string $__primaryKey = 'id'; // default public int $id; public ?string $name = null; public ?string $extref = null; public int $create; public int $edit; } ``` ## Custom Database ```php protected static ?array $__databaseConfig = [ 'host' => ADDRESSDB_DBHOST, 'user' => ADDRESSDB_DBUSER, 'pass' => ADDRESSDB_DBPASS, 'name' => ADDRESSDB_DBNAME ]; ``` ## Static Methods ```php $model = MyModel::get(123); // by ID, returns ?static $model = MyModel::getFirst(['name' => 'foo']); // first match $all = MyModel::getAll($filter, $limit, $offset, $order); $all = MyModel::search($filter); // alias for getAll $count = MyModel::count($filter); ``` ## Filter Operators | Prefix | SQL | Example | |--------|-----|---------| | (none) | LIKE %...% | `['name' => 'foo']` | | `=` | = exact | `['=name' => 'foo']` | | `!` | != / NOT IN | `['!status' => 'deleted']` | | `>` `<` `>=` `<=` | comparison | `['>create' => $timestamp]` | **Special values:** ```php ['status' => null] // IS NULL ['!status' => null] // IS NOT NULL ['id' => [1, 2, 3]] // IN (1, 2, 3) ['!id' => [1, 2, 3]] // NOT IN (1, 2, 3) ``` ## Ordering ```php MyModel::getAll([], null, 0, ['column' => 'name', 'dir' => 'ASC']); ``` ## Instance Methods ```php $model->save(); // insert or update $model->delete(); $model->isLoaded(); $model->getId(); $model->toArray(); $model->toJson(); $model->getJournalHistory(); // returns change history ``` ## Hooks ```php public function validate(): array { $errors = []; if (empty($this->name)) $errors[] = 'Name required'; return $errors; // empty = valid } protected function beforeSave(bool $isInsert): bool { return true; // false cancels save } protected function afterSave(bool $isInsert, array $changes): void { // $changes = ['field' => ['old' => x, 'new' => y]] } ``` ## Journaling Automatic change tracking to `Journal` table. Configure field labels: ```php protected static array $__journalFieldMap = [ 'name' => 'Name', 'extref' => 'External Reference', ]; ``` Disable per model: ```php protected static bool $__enableJournaling = false; ``` ## Auto-timestamps If properties exist, they're set automatically on save: - `create`, `create_by` - on insert - `edit`, `edit_by` - on insert/update ## Magic Properties with Intellisense Use `@property-read` for lazy-loaded relations: ```php /** * @property-read ADBNetzgebietRelations $relations */ class ADBNetzgebiet extends mfBaseModelV2 { private ?ADBNetzgebietRelations $__relations = null; public function __get(string $name) { if ($name === 'relations') { return $this->__relations ??= $this->loadRelations(); } return null; } public function loadRelations(): ADBNetzgebietRelations { // ... } } ``` Typed relation class for IDE support: ```php class ADBNetzgebietRelations { /** @var array{id: int, name: string}[] */ public array $networks = []; /** @var array{id: int, name: string}[] */ public array $campaigns = []; } ``` Usage with full autocomplete: ```php $model = ADBNetzgebiet::get(1); $model->relations->networks; // IDE knows this is array{id: int, name: string}[] ```