Model
A model extends Hubleto\Erp\Model. It describes one database table: its columns, relations, indexes, and how the table and the form look in the user interface. The model does not run queries. The record manager does.
Anatomy
apps/Customers/Models/Tag.php
<?php
namespace Hubleto\App\Community\Customers\Models;
use Hubleto\Framework\Db\Column\Color;
use Hubleto\Framework\Db\Column\Varchar;
class Tag extends \Hubleto\Erp\Model
{
public string $table = 'customer_tags';
public string $recordManagerClass = RecordManagers\Tag::class;
public ?string $lookupSqlValue = '{%TABLE%}.name';
public function describeColumns(): array
{
return array_merge(parent::describeColumns(), [
'name' => (new Varchar($this, $this->translate('Name')))->setRequired(),
'color' => (new Color($this, $this->translate('Color')))->setRequired(),
]);
}
public function describeTable(): \Hubleto\Framework\Description\Table
{
$description = parent::describeTable();
// $description->ui['title'] = $this->translate('Customer Tags');
$description->ui['addButtonText'] = $this->translate('Add Customer Tag');
$description->ui['showHeader'] = true;
$description->ui['showFulltextSearch'] = true;
$description->ui['showFooter'] = false;
return $description;
}
}
| Member | Purpose |
|---|---|
$table |
Name of the table (plural, snake_case). |
$recordManagerClass |
The record manager that works with the table. |
$lookupSqlValue |
SQL that is shown when a record is selected in a lookup. Uses {%TABLE%}. |
$lookupUrlDetail |
URL of the detail of a record. Uses {%ID%}. |
$relations |
HAS_MANY, HAS_ONE and BELONGS_TO relations, UPPER_CASE names. |
describeColumns() |
The columns. Merge with parent::describeColumns(). |
describeTable() |
Texts, visibility and filters of the table. |
describeForm() |
Defaults and texts of the form. |
describeInput($column) |
Customizes the input of one column. |
indexes() |
Indexes. |
onBefore*, onAfter* |
Callbacks of saving and deleting. Call parent::. |
migrations() |
The migrations of the model (found in Models/Migrations). |
upgradeSchema() |
Creates or upgrades the table. Called in installApp(). |
upgradeForeignKeys() |
Adds the foreign keys. Called in install round 3 and by php hubleto migrate. |
Members of a model.
Columns
The column types are in Hubleto\Framework\Db\Column: PrimaryKey, Varchar, Text, Integer, Decimal, Currency, Boolean, Date, DateTime, Time, Year, Lookup, Json, Email, Password, Color, Image, File and Virtual. Each column is a fluent object:
apps/Deals/Models/Deal.php (excerpt)
'identifier' => (new Varchar($this, $this->translate('Deal Identifier')))->setCssClass('badge badge-info')->setDefaultVisible(),
'title' => (new Varchar($this, $this->translate('Title')))->setRequired()->setDefaultVisible()->setCssClass('font-bold'),
'id_customer' => (new Lookup($this, $this->translate('Customer'), Customer::class))->setDefaultValue($this->router()->urlParamAsInteger('idCustomer')),
'id_contact' => (new Lookup($this, $this->translate('Contact'), Contact::class)),
'id_lead' => (new Lookup($this, $this->translate('Lead'), Lead::class))->setReadonly(),
'version' => (new Integer($this, $this->translate('Version'))),
// 'price' => (new Decimal($this, $this->translate('Price')))->setDecimals(2),
'price_excl_vat' => new Decimal($this, $this->translate('Price excl. VAT')),
'price_incl_vat' => new Decimal($this, $this->translate('Price incl. VAT')),
'id_currency' => (new Lookup($this, $this->translate('Currency'), Currency::class))->setFkOnUpdate('RESTRICT')->setFkOnDelete('SET NULL')->setReadonly(),
'date_expected_close' => (new Date($this, $this->translate('Expected close date'))),
'id_owner' => (new Lookup($this, $this->translate('Owner'), User::class))->setReactComponent('InputUserSelect')->setDefaultValue($this->authProvider()->getUserId()),
See Understanding columns in a model and describeColumns().
Callbacks
The callbacks have a fixed signature and must call parent:::
| Callback | Receives → returns |
|---|---|
onBeforeValidate($record), onAfterValidate($record) |
record → record |
onBeforeCreate($record), onAfterCreate($saved) |
record → record |
onBeforeUpdate($record) |
record → record |
onAfterUpdate($original, $saved) |
records → record |
onBeforeDelete($id), onAfterDelete($id) |
int → int |
onAfterLoadRecord($record), onAfterLoadRecords($records) |
record(s) → record(s) |
Callbacks.
apps/Customers/Models/Customer.php (excerpt)
public function onAfterUpdate(array $originalRecord, array $savedRecord): array
{
$savedRecord = parent::onAfterUpdate($originalRecord, $savedRecord);
if (isset($savedRecord["TAGS"])) {
$helper = $this->getService(Helper::class);
$helper->deleteTags(
array_column($savedRecord["TAGS"], "id"),
$this->getModel("Hubleto/App/Community/Customers/Models/CustomerTag"),
"id_customer",
$savedRecord["id"]
);
}
return $savedRecord;
}
Migrations
A migration is a class in Models/Migrations named <Model>_<NNNN>. The first migration creates the table and the next ones change it. The model finds its migrations by the file-name prefix and runs the missing ones in upgradeSchema().
apps/Customers/Models/Migrations/Customer_0002.php
<?php
namespace Hubleto\App\Community\Customers\Models\Migrations;
use Hubleto\Framework\Migration;
class Customer_0002 extends Migration
{
public function upgradeSchema(): void
{
$this->db->execute("alter table `customers` change `customer_id` `company_id` varchar(255)");
}
public function downgradeSchema(): void
{
$this->db->execute("alter table `customers` change `company_id` `customer_id` varchar(255)");
}
public function upgradeForeignKeys(): void
{
}
public function downgradeForeignKeys(): void
{
}
}
