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

  1. Title, short description and description per language (property_description[language_id]); the name column is the default language title, otherwise the first filled language; empty raises an error on the title-<default> field.
  2. Coordinates: only a valid pair (|latitude| ≤ 90, |longitude| ≤ 180), comma replaced by a point, rounded to 7 decimals; empty = no point.
  3. Content scope check of the client (operator).
  4. Validation of power of attorney rows (if mandate_form = 1).
  5. Data sheet normalisation (Dlbtproperty::normalize()), rooms (normalizeRooms()) and area calculation (computeAreas()).
  6. Condominium: parent_property_id cannot point to itself (then 0).
  7. Labels: the first active chip label with an engine handler, otherwise the first active label, goes into the legacy label_id column.
  8. New record: addProperty() (response carries property_id); existing: editProperty(); store assignment (sync_stores = 1) via savePropertyStores().
  9. saveDescriptions(), labels (label::setObjectLabels('property', …)), saveRooms(), saveMeters(), saveMandates() (response carries mandate_ids).
  10. Read-back (getProperty()); with coordinates the point goes into the shared geo store (dlbtgeo->ingest(Dlbtproperty::geoSpec(...)), source type property, one property = one point); on failure the save stays successful with geo_warning.
  11. 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.

TableMain fields
propertyname, 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_storeproperty_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.

Related topics: property map permissions