Validation settings 

Every field of Configuration/AcademicPersons/Settings.yaml carries a list of flags that say whether it is required, read only or disabled, and what kind of value it takes. One list drives both editing contexts:

  • the TYPO3 backend record editor (FormEngine), through generated TCA, and
  • the editing frontend of EXT:academic_persons_edit.

This is why the file ships with academic_persons, which owns the records and their TCA, and not with the editing extension. The backend half applies even when the editing extension is not installed. Where the fields live - the profile , special , contracts and documentSections maps - is documented on the Profile sections page; this page is about the flags.

Where the flags are declared 

A profile, contract or contact field carries its flags as a list:

profile:
  gender:
    section: information
    fieldType: select
    renderType: select
    validators:
      - required
  firstName:
    section: information
    fieldType: input
    renderType: text
    validators:
      - readonly
      - disabled
Copied!

A document section carries a map from field to flag list, with an expanded map for a rich text field:

documentSections:
  publications:
    validators:
      title:
        - required
      year:
        - required
        - number
      link:
        - url
      description:
        editor:
          type: ckeditor
          limit: 500
Copied!

A field without flags is unconfigured: it is editable, not required, and no validator runs for it. A field that is not listed at all is not offered by the editing frontend.

Available flags 

Flag names are matched case insensitively. Anything not listed here is kept in the list and has no effect.

Flag Effect
required The field must not be empty. Adds a not empty validation in the frontend and marks the field required in the backend.
disabled The field must not be edited at all. See the note below.
readonly The field is shown but cannot be written.
frontendreadonly The field is shown but cannot be written in the editing frontend. The backend record editor keeps it editable. See the note below.
email The value must be a valid email address; the field is rendered as an email input and the TCA column becomes an email column.
url The value must be a valid URL; the field is rendered as a URL input. The TCA column is untouched.
number The field is rendered as a number input and the TCA column becomes a number column. No additional server side validation is performed.
date The field is rendered as a date input. The TCA column keeps its own datetime configuration.
tel The field is rendered as a telephone input. No phone number format is enforced, and the TCA column is untouched.
textarea The field is rendered as a multi line text control. The TCA column is untouched.
html The field is rich text: the editing frontend renders the rich text editor and sanitises the submitted markup. The TCA column is untouched.

Only required , email and url run a validator on the server; the other flags select the control and the input normalisation. Validator class names and validator options cannot be put in the list.

Character limits 

A rich text field may limit the number of readable characters - markup is not counted. A profile or contract field declares it next to its render type, a document field in its editor block:

profile:
  miscellaneous:
    section: aboutme
    fieldType: textarea
    renderType: ckeditor
    characterLimit: 1000
    validators:
      - html

documentSections:
  publications:
    validators:
      description:
        editor:
          type: ckeditor
          limit: 500
Copied!

The limit is effective only on a ckeditor control; on any other control it is ignored. It is checked on the server and shown by the editing frontend; it is never copied into the TCA, because FormEngine's max would count the markup.

Fields that are locked by default 

The three name fields ship as readonly and disabled :

profile:
  firstName:
    validators:
      - readonly
      - disabled
  middleName:
    validators:
      - readonly
      - disabled
  lastName:
    validators:
      - readonly
      - disabled
Copied!

This is intentional. Profile names are usually owned by the connected frontend user record - commonly fed from a directory service such as LDAP or Active Directory, and synchronised into the profile - so they must not be overwritten from an editing form.

The consequences, which surprise people who did not expect them:

  • First name, Middle name and Last name are read only in the backend record editor, for every backend user.
  • The same three fields are rendered locked in the editing frontend, and a value submitted for them is discarded on the server.

If the profile names are maintained in TYPO3 rather than synchronised from elsewhere, remove the two flags as described below. Where some profiles are synchronised and others are created by editors, lock the names on the synchronised ones only, with managed fields.

Effects in the TYPO3 backend 

The flags of every section are merged into the TCA of the matching table, so a field locked with readonly or disabled is read only in the record editor and a required field is marked as such. frontendreadonly is the one lock that does not reach the TCA. The sections map to these tables:

Section Table
profile fields and special.skipSync tx_academicpersons_domain_model_profile
contracts.fields tx_academicpersons_domain_model_contract
contracts.contactSections.emailAddresses tx_academicpersons_domain_model_email
contracts.contactSections.phoneNumbers tx_academicpersons_domain_model_phone_number
contracts.contactSections.physicalAddresses tx_academicpersons_domain_model_address
every other documentSections entry tx_academicpersons_domain_model_profile_information , as columnsOverrides of the record type of that section

special.hidden is the one exception. Its flags decide whether owners may show or hide their profile in the profile editor, and an installation sets them when editors are meant to decide instead, so they never make the backend checkbox Visible read only.

The property name is translated to the database column automatically: firstName addresses first_name ; a field that names a fieldName addresses that column instead.

Every column takes the flags of one field. When two fields of the profile, of the contracts or of one contact section, a profile field and a special field, or two special fields name the same column, the column gets the flags of the field applied later, and the flags of the earlier field are lost. The profile fields are applied in section order, then the special fields. A site package that adds a second profile field with fieldName: teaching_area decides whether the teaching area is required in the backend, whatever the shipped teachingArea field says. The same holds for two timeline sections of one record type. The console command academic:upgrade:check of EXT:academic_base and the status report under Academic Persons name such a column as a warning shared-column , with the table, the column and the fields. Give each field a column of its own.

Two cases are not named. Two fields with the same property name, and a special field named like the property of a profile field, are combined into one before the flags are applied, so the later one replaces the earlier and no column is shared. And a project field is checked against the TCA as it is before the flags are applied, the warning against the TCA after them. Where another field of the same column turns it into an email or number column, the project field can be refused by one and accepted by the other.

The seven timeline sections share one table, so their flags apply to their record type only: a required title of publications does not make the title of a lecture required. The fieldType and renderType of a field never reach the TCA - the column keeps the type its TCA file declares.

The flags are applied once the TCA is compiled, after every Configuration/TCA/Overrides file. A site package that replaces one of these columns keeps what the settings say about it, and a required or readOnly its TCA override sets on a configured column is replaced by the settings. State a lock in the settings instead. A value that has to differ in the backend only is set by a listener of \TYPO3\CMS\Core\Configuration\Event\AfterTcaCompilationEvent ordered after academic-persons/apply-settings-to-tca, see Breaking: Settings apply after the TCA overrides.

A project field, declared with custom: true , gets its flags only when its column may be used: the column is in the profile TCA, it is no system column and no column of the shipped profile model, its type is input, text, email, link, number or check, and the renderer and validators of the field fit that type. Any other column gets nothing and raises a deprecation notice naming the field, the column and the reason. The backend and the install tool keep working. A regular field whose column the TCA does not have is left out without a notice.

Effects in the editing frontend 

When EXT:academic_persons_edit is installed, the same flags are used three times:

  1. The control is rendered with the matching disabled , readonly and required attributes and the input type the flags select.
  2. required , email and url add server side validation of the submitted data, and a character limit is enforced.
  3. A disabled , readonly or frontendreadonly property is never written to the record, whatever the request contains. This is deliberate: it protects already stored data, and it is what prevents a locked field from being emptied when a form is submitted. A submitted value for it is ignored and the other values of the request are stored, so a contract or contact with a locked field is saved as usual. The same holds for a field the synchronisation owns on the record, see In the profile editor.

Validation never falls back from one section to another: a contact record is validated against its contact section, a timeline entry against the section of its record type, and the profile against its profile sections.

Overriding the flags 

The flags live in the map that carries the field, so changing them means overriding that map - see Overriding the file. The files are merged recursively, so an override names the field and its validators list and nothing else. The list itself is replaced as a whole, which is how a flag is dropped.

Example - making the profile names editable again, in the backend and in the editing frontend. The three name fields ship with readonly and disabled ; an empty list clears them, and every other key of those fields, of the other fields and of the layout stays as shipped:

profile:
  firstName:
    validators: []
  middleName:
    validators: []
  lastName:
    validators: []
Copied!

A flag is added the same way, by restating the list with it:

profile:
  title:
    validators:
      - required
Copied!

Example - keeping the synchronised profile names away from their owners while backend editors can still correct them. frontendreadonly replaces both shipped flags, and required keeps the first and last name required in the backend record editor, as the TCA of the profile table declares them:

profile:
  firstName:
    validators:
      - required
      - frontendreadonly
  middleName:
    validators:
      - frontendreadonly
  lastName:
    validators:
      - required
      - frontendreadonly
Copied!

There is no TypoScript and no site set equivalent for these settings.

Migrating a pre-3.0 override 

Before 3.0 the file had two top-level maps, validations with one flag list per record type and profileInformationsTypes with the seven timeline entry types, and the manual told integrators to restate the complete validations block in the site package. Such a file keeps working after the update: the two keys are mapped onto the section maps at runtime, before the settings graph is built, and a warning naming the package and the key is logged once per cache build. The mapping is transitional and is removed in academic_persons 4.0, so the override should be rewritten.

The console command prints the replacement:

vendor/bin/typo3 academic:persons:settings:migrate
Copied!

For every active package that still ships a legacy key it prints the package, the keys it found, one comment line per entry that could not be mapped, and the four maps profile , special , contracts and documentSections as the runtime mapping produces them - the complete document that replaces the legacy keys in that package's file. It exits with 1 when such a package exists and with 0 otherwise, so a deployment pipeline can run it as a check. The command never writes the file: the override lives in a site package that is under version control and usually deployed read only, so the printed maps are pasted into the file after review, and the TYPO3 caches are flushed afterwards. When EXT:reports is installed, the Status report lists the same packages under Academic Persons as a warning.

The printed maps restate everything the runtime produces. Once they replace the legacy keys, vendor/bin/typo3 academic:persons:settings:migrate --delta reduces the file to the entries that differ from what the packages loaded before it configure - see Overriding the file.

How the legacy keys map:

Legacy key Mapped onto
validations.profile.<property> profile.<field>.validators
validations.contract.<property> contracts.fields.<field>.validators
validations.emailAddress.{email, type} contracts.contactSections.emailAddresses.fields.{emailAddress, emailAddressType}.validators
validations.phoneNumber.{phoneNumber, type} contracts.contactSections.phoneNumbers.fields.{phoneNumber, phoneNumberType}.validators
validations.physicalAddress.<property> contracts.contactSections.physicalAddresses.fields.<field>.validators , type onto physicalAddressType
validations.profileInformation.<property> documentSections.<section>.validators.<field> of every timeline section; yearStart , yearEnd and bodytext onto from , to and description
profileInformationsTypes.<section> the label of documentSections.<section> ; its type and fieldName are reported, not applied

A field is matched by its key or by the property it names, so emailAddress.email reaches the emailAddress field whose propertyName is email . A legacy set decides the six flags the old shape knew - required , readonly , frontendreadonly (added in 2.4), disabled , email and number - for every field of its target: a field the set does not list has none of them, exactly as an unlisted property was unconfigured before, which is what made the 2.x example above unlock the profile names by not listing them. The flags the old shape could not express - url , date , tel , textarea , html - stay as the section maps declare them.

Two things are not mapped and are reported by the command and in the log:

  • A property the section maps do not know, and an eighth timeline entry type declared under profileInformationsTypes , are skipped. The type needs a profile relation and a TCA column the settings never created; the Breaking entry on the section based settings describes how to keep one.
  • The type and fieldName of a timeline entry type are not applied. Until 2.4 the two generated the inline column of the profile table, so overriding one moved the backend relation and the frontend selection together; since 3.0.0 the seven relations are declared by the TCA of the profile table, and applying the override would move the frontend half alone - records created in the editing frontend would be invisible in the backend, and the other way round. The section keeps the record type and the relation field that match the TCA, and the value the override named is printed as a note. Act on that note: a timeline type of your own needs its own column in a TCA override of the profile table, as The document sections and the Upgrading from 2.4 to 3.0 page describe.