doc/src/repositories/metadata.md
# Basic metadata structure
Metadata for entities are always organized into individual XML files. Each file uses the SimpleFM metadata namespace and
the root element must specify at least the class name of the entity, including its namespace, as well as the layout on
which the repository will operate on.
To support auto completion in IDEs, it is advised to include the schema location of the official XSD file. It will be
included in the following example but excluded from all further ones for simplicity reasons:
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity
xmlns="uri:soliantconsulting.com:simplefm:entity-metadata"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="uri:soliantconsulting.com:simplefm:entity-metadata
https://soliantconsulting.github.io/SimpleFM/entity-metadata-5-1.xsd"
class-name="My\Entity\SampleEntity"
layout="sample-layout"
/>
```
Additionally, you can define an interface name on the root element, which will be used for automatically creating entity
proxies for lazy loading:
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity … interface-name="My\Entity\SampleEntityInterface"/>
```
# Field properties
The most common type you are going to define in your metadata are field properties. These are any kind of fields in the
layout which can be mapped to scalar values, `Decimal` or `DateTimeImmutable`. When defining a field type, the following
three attributes are mandatory:
name
: The name of the field in your layout
property
: The property name on your entity
type
: The type to which the value will be cast to on your entity. The following built-in types are supported:
* **boolean**: will treat any value other than "0" or "" as true
* **date-time**: will treat the value as `DateTimeImmutable`
* **date**: will treat the value as `DateTimeImmutable` and convert it to a pure date
* **decimal**: will treat the numeric value as `Decimal` object
* **float**: will treat the numeric value as float
* **integer**: will treat the numeric value as integer
* **nullable-string**: will treat the value as string but convert an empty string to null
* **stream**: will treat the value as lazy loaded `StreamInterface`
* **string**: will treat the value as string
* **time**: will treat the value as `DateTimeImmutable` and convert it to a pure time
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<field name="Name" property="name" type="string"/>
</entity>
```
Additionally, the field element supports the following two boolean attributes which default to `false`:
read-only
: Tells the repository to not persist this property
repeatable
: Treats the field as a set of values
# Record ID
If you need to access the record ID of a record, you can specify it via a special `<record-id/>' element:
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<record-id property="recordId"/>
</entity>
```
# Relations
Sometimes your layout defines relations to other tables. For that reason, SimpleFM supports many-to-one, one-to-many and
one-to-one relations. For one-to-many relations, SimpleFM will create lazy-loaded collections, while for both
many-to-one and one-to-one relations it will create a lazy-loaded proxy.
!!!note "Proxy interface"
When using any to-one relation, you need to define an interface name on the target entity's metadata, so that the
repository can create a proxy for it. The only exception is when the relation has
[eager hydration](#eager-hydration) enabled.
## One-to-many
A one-to-many relation is the simplest of the three relations. It is defined by the following attributes:
property
: The property name on your entity
target-table
: The table of the foreign entity as it shows on the layout
target-entity
: The class name of the mapped entity
target-field-name
: The name of the identifying ID field
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<one-to-many
property="sampleChildren"
target-table="children"
target-entity="My\Entity\SampleEntityChild"
target-field-name="ID"
/>
</entity>
```
## Many-to-one
A many-to-one relation is set up similarly as the [one-to-many](#one-to-many) relation and requires the same attributes
including a few additional ones:
name
: The name of the field containing the foreign ID
target-property-name
: The property name on the mapped entity containing the ID
Optionally, you can mark the relation as read-only by setting the `read-only` property to `true`.
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<many-to-one
name="ParentID"
property="sampleParent"
target-table="parents"
target-entity="My\Entity\SampleEntityParent"
target-field-name="ID"
target-property-name="id"
/>
</entity>
```
## One-to-one
When it comes to one-to-one relations, there are two types of it: the owning side and the inverse side.
### Owning side
The owning side takes the exact same attributes as the [many-to-one](#many-to-one) relation, including the optional
`read-only` attribute.
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<one-to-one-owning
name="ParentID"
property="sampleParent"
target-table="parents"
target-entity="My\Entity\SampleEntityParent"
target-field-name="ID"
target-property-name="id"
/>
</entity>
```
### Inverse side
While the owning side mirrors the behavior of the many-to-one relation, the inverse side mirrors that of the
[one-to-many](#one-to-many) relation and requires the same arguments:
```xml
<?xml version="1.0" encoding="utf-8"?>
<entity …>
<one-to-one-inverse
property="sampleChildren"
target-table="children"
target-entity="My\Entity\SampleEntityChild"
target-field-name="ID"
/>
</entity>
```
## Eager hydration
Every relation can be eagerly hydrated when the sparse record contains all information to fully hydrate the parent or
child entity. To enable eager hydration, set the `eager-hydration` property on the relation to `true`.
While this gives you additional hydration overhead for each relation, it also saves you from doing additional queries
against FileMaker. Using eager hydration should only be considered when you are using specific relations often enough.