Saving process and data model of the property form
Steps of saving a property with validation, coordinate and label handling, the pre-migration state, writing the geo store, master and related tables, and the public methods of the owner model.
The form (masterdata/property.form, edit permission) has two columns (40/60). Saving (masterdata/property.save, canSave(route, property_id); as there is no add key, a new record also needs edit) writes basic data, descriptions, labels, rooms, meters and powers of attorney in one request.
Saving steps
- Title, short description and description per language (
property_description[language_id]); thenamecolumn is the default language title, otherwise the first filled language; empty raises an error on thetitle-<default>field. - Coordinates: only a valid pair (|latitude| ≤ 90, |longitude| ≤ 180), comma replaced by a point, rounded to 7 decimals; empty = no point.
- Content scope check of the client (operator).
- Validation of power of attorney rows (if
mandate_form = 1). - Data sheet normalisation (
Dlbtproperty::normalize()), rooms (normalizeRooms()) and area calculation (computeAreas()). - Condominium:
parent_property_idcannot point to itself (then 0). - Labels: the first active chip label with an engine handler, otherwise the first active label, goes into the legacy
label_idcolumn. - New record:
addProperty()(response carriesproperty_id); existing:editProperty(); store assignment (sync_stores = 1) viasavePropertyStores(). saveDescriptions(), labels (label::setObjectLabels('property', …)),saveRooms(),saveMeters(),saveMandates()(response carriesmandate_ids).- Read-back (
getProperty()); with coordinates the point goes into the shared geo store (dlbtgeo->ingest(Dlbtproperty::geoSpec(...)), source typeproperty, one property = one point); on failure the save stays successful withgeo_warning. - Success: "Success: Property saved."; no redirect, the form's passive listener writes the new id into the hidden
property_id.
If the data sheet columns are still missing, saving writes the basic data and states in a warning what was not saved; the form shows a yellow box with the migration log row and the chain blocker, and with system/update + install a "Retry migrations" button (system/update.retry).
Data model
Table names carry the installation's own prefix in the database.
| Table | Main fields |
|---|---|
property | name, identifier, address, owner_company_id, match_value, label_id, note, status, created_by; address: operator_company_id, country_code, postcode, city, street_name, street_type, house_number, building, staircase, floor, door, lot_number; data sheet: property_type (the first type), property_types, property_uses, areas, latitude, longitude, details (JSON), cover_doc_id, parent_property_id |
property_description | (property_id, language_id): title, short_description, description |
property_to_store | property_id, store_id |
Foreign tables referenced (not written): company, doc_link (object_type = property), label_link, contract (deletion protection), the geo store.
Owner model
admin/model/masterdata/property.php. Public methods used by other modules: getProperty(), getProperties(), getActiveProperties() (contract), getOperatedProperties() and hasOperatorColumn() (tourism tax), getValidMandate(), getMandatedPropertyIds(), mandateCovers() (contract), getGeocodeCandidates(), setCoordinates() (geo map), countRoomsByType() (room type master deletion protection), getPropertyStores(), savePropertyStores(). Catalog model: getPropertyForView() (active + assigned to the current store), getDescription(), getRooms(), getPropertyForApi(), getPropertyChanges(). The Dlbtproperty library is an SQL-free field registry and calculator.
Helper endpoints
labelsearch (at most 20 active labels), labelcreate (dlbtlabel->ensureLabel), companies (shared company picker), companysearch (at least 2 characters, 20 active companies; not filtered by content scope — any active company can be owner). Map on the form: Google Maps with the API key of type "maps"; "From address" geocodes the structured address.