-
Notifications
You must be signed in to change notification settings - Fork 13
Models
Models are the basic representation of interactions with the database. There are two types of models, a read-only model and a write-only model, which are both dynamically generated from a model schema.
All model schemas are located in models/schema/
and extend the ModelSchema interface. Here's an example schema:
<?hh // strict
class ExampleSchema implements ModelSchema {
public function getFields(): Map<string, ModelField> {
return Map {
'ID' => ModelField::int_field('id'),
'Name' => ModelField::string_field('name'),
};
}
public function getTableName(): string {
return 'example';
}
public function getIdField(): string {
return 'id';
}
}
getIdField()
and getTableName()
are fairly self-descriptive, but let's take a closer look at getFields()
.
public function getFields(): Map<string, ModelField> {
return Map {
'ID' => ModelField::int_field('id'),
'Name' => ModelField::string_field('name'),
};
}
Here we define a mapping between data fields in our model and the database columns, as well as establish types. In this example, ID
will be an int, and will be generated into a getID()
function in the read-only model, setID()
in the write-only model, and will map to an int column in the database called id
. Other types of field types can be found here.
For the above example, upon running our build script, a read-only model will be generated:
<?hh
/**
* This file is partially generated. Only make modifications between BEGIN
* MANUAL SECTION and END MANUAL SECTION designators.
*
* @partially-generated SignedSource<<7d8f29e8e807ty578602e6e5c9jk5a07>>
*/
final class Example {
private function __construct(private Map<string, mixed> $data) {
}
public static function load(int $id): ?Example {
$result = DB::queryFirstRow("SELECT * FROM example WHERE id=%s", $id);
if (!$result) {
return null;
}
return new Example(new Map($result));
}
public function getID(): int {
return (int) $this->data['id'];
}
public function getName(): string {
return (string) $this->data['name'];
}
/* BEGIN MANUAL SECTION Example_footer */
/* END MANUAL SECTION */
}
To generate the object, we only have to call Example::load($id)
, and it will go out to the database and populate our object for us. Here, id
is whatever we specified our ID Field to be in the schema. In the event we need to add additional methods to the model, we can do so between the two comments at the bottom of the class, and it will be carried over across re-generations of the file.
When we run the build script on the avoid example, the following write-only model will be generated (called a Mutator):
<?hh // strict
/**
* This file is partially generated. Only make modifications between BEGIN
* MANUAL SECTION and END MANUAL SECTION designators.
*
* @partially-generated SignedSource<<3067df1e73529a1661b3f73dcc17f712>>
*/
final class ExampleMutator {
private Map<string, mixed> $data = Map {
};
private function __construct(private ?int $id = null) {
}
public static function create(): this {
return new ExampleMutator();
}
public static function update(int $id): this {
return new ExampleMutator($id);
}
public static function delete(int $id): void {
DB::delete("announcement", "id=%s", $id);
}
public function save(): int {
// Code left out for example
}
public function checkRequiredFields(): void {
// Code left out for example
}
public function setID(int $value): this {
$this->data["id"] = $value;
return $this;
}
public function setName(string $value): this {
$this->data["name"] = $value;
return $this;
}
/* BEGIN MANUAL SECTION ExampleMutator_footer */
/* END MANUAL SECTION */
}
Mutators are how we create, update, and delete objects in the database. To create a new Example
, we would run:
ExampleMutator::create()
->setID($id)
->setName($name)
->save();
This will create a new ExampleMutator, set the fields, verify all the required fields are set, and then save it out. If we are updating a pre-existing object, instead of creating a new one, we would do something like this:
ExampleMutator::update($id)
->setName($name)
->save();
This will allow us to update the pre-existing object with ID = $id
. Like the create method, it still verifies all required fields are set before saving out. To delete, we just run
ExampleMutator::delete($id);
Just like with the read-only model, there is a place at the bottom of the class to add your own custom methods which will be carried across re-generations.