# apostrophe-schemas
# Inherits from: apostrophe-module
# apos.schemas
This module provides schemas, a flexible and fast way to create new data types by specifying the fields that should make them up. Schemas power apostrophe-pieces, apostrophe-widgets, custom field types in page settings for apostrophe-custom-pages and more.
A schema is simply an array of "plain old objects." Each object describes one field in the schema
via type
, name
, label
and other properties.
See the schema guide for a complete overview and list of schema field types. The methods documented here on this page are most often used when you choose to work independently with schemas, such as in a custom project that requires forms.
# Methods
# createRoutes() [routes]
# pushAssets()
# pushCreateSingleton()
# compose(options, module)
Compose a schema based on addFields, removeFields, orderFields and, occasionally, alterFields options. This method is great for merging the schema requirements of subclasses with the schema requirements of a superclass. See the apostrophe-schemas documentation for a thorough explanation of the use of each option. The alterFields option should be avoided if your needs can be met via another option.
If present, the module
option is used to resolve method
names lacking a module name, for instance when a method name
is given for the choices
property of a select
field.
# setModuleName(field, module)
Recursively set moduleName property of the field and any subfields,
as might be found in array or object fields. module
is an actual module
# refine(schema, _options)
refine is like compose, but it starts with an existing schema array and amends it via the same options as compose.
# toGroups(fields)
Converts a flat schema (array of field objects) into a two dimensional schema, broken up by groups
# subset(schema, fields)
Return a new schema containing only the fields named in the
fields
array, while maintaining existing group relationships.
Any empty groups are dropped. Do NOT include group names
in fields
. If fields
contains a property that is not a
field name but does match the idField
or idsField
property
of a field, that also includes the field in the subset. This is
convenient when basing this call on the keys in req.body
.
# newInstance(schema)
Return a new object with all default settings defined in the schema
# subsetInstance(schema, instance)
# empty(schema, object)
Determine whether an object is empty according to the schema. Note this is not the same thing as matching the defaults. A nonempty string or array is never considered empty. A numeric value of 0 is considered empty
# indexFields(schema, object, texts)
Index the object's fields for participation in Apostrophe search unless
searchable: false
is set for the field in question
# convert(req, schema, from, data, object, callback)
Convert submitted data
, sanitizing it and populating object
with it.
# isVisible(schema, object, name)
Determine whether the given field is visible based on showFields options of all fields
# export(req, schema, to, object, output, callback)
Export sanitized 'object' into 'output'
# joinDriver(req, method, reverse, items, idField, relationshipsField, objectField, options, callback)
Driver invoked by the "join" methods of the standard join field types.
All arguments must be present, however relationshipsField may be undefined to indicate none is needed.
# join(req, schema, objectOrArray, withJoins, callback)
Carry out all the joins in the schema on the specified object or array of objects. The withJoins option may be omitted.
If withJoins is omitted, null or undefined, all the joins in the schema are performed, and also any joins specified by the 'withJoins' option of each join field in the schema, if any. And that's where it stops. Infinite recursion is not possible.
If withJoins is specified and set to "false", no joins at all are performed.
If withJoins is set to an array of join names found in the schema, then only those joins are performed, ignoring any 'withJoins' options found in the schema.
If a join name in the withJoins array uses dot notation, like this:
_events._locations
Then the objects are joined with events, and then the events are further joined with locations, assuming that _events is defined as a join in the schema and _locations is defined as a join in the schema for the events module. Multiple "dot notation" joins may share a prefix.
Joins are also supported in the schemas of array fields.
# addFieldType(type)
Add a new field type. The type
object may contain the following properties:
# name
Required. The name of the field type, such as select
. Use a unique prefix to avoid
collisions with future official Apostrophe field types.
# converters
Required. An object with string
and form
sub-properties, functions which are invoked for
strings (as often needed for imports) and Apostrophe-specific form submissions respectively.
These are functions which accept:
req, data, name, object, field, callback
Sanitize the contents of data[name]
and copy values
known to be safe to object[name]
. Then invoke the callback.
field
contains the schema field definition, useful to access
def
, min
, max
, etc.
If form
can use the same logic as string
you may write:
form: 'string'
To reuse it.
# empty
Optional. A function which accepts field, value
and returns
true only if the field should be considered empty, for purposes of
deciding if the entire object is empty or not.
# bless
Optional. A function which accepts req, field
and calls self.apos.utils.bless
on any schemas nested within field
, so that editors are allowed to edit content. See
the implementation of the areas
field type for an example.
# index
Optional. A function which accepts value, field, texts
and pushes
objects containing search engine-friendly text onto texts
, if desired:
index: function(value, field, texts) {
var silent = (field.silent === undefined) ? true : field.silent;
texts.push({ weight: field.weight || 15, text: (value || []).join(' '), silent: silent });
}
Note that areas are always indexed.
# getFieldType(typeName)
# addFilters(schema, options, cursor)
Given a schema and a cursor, add filter methods to the cursor
for each of the fields in the schema, based on their field type,
if supported by the field type. If a field name exists in options.override
this is done even if such a filter is already present on the cursor object.
# joinFilterChoices(field, cursor, valueField)
You don't need to call this. It is called for you when you invoke toChoices
for any
cursor filter based on a join. It delivers an array of choice objects to its callback.
# addJoinSlugFilter(field, cursor, suffix)
You don't need to call this. It is called for you as part of the mechanism that adds cursor filter methods for all joins.
If you named your join properly (leading _), you also get a filter
without the _
that accepts slugs rather than ids - it's suitable
for public use in URLs (and it's good naming because the public would find the _ weird).
If you're wondering, you should have had the leading _ anyway to keep it from persisting the loaded data for the join back to your doc, which could easily blow mongodb's doc size limit and in any case is out of data info in your database.
# pageServe(req)
When a page is served to a logged-in user, make sure the session contains a blessing for every join configured in schemas for doc types
# bless(req, schema)
Bless a schema. Makes a note in the user's session that the various area, widget and array schema options found within this schema are genuine. This allows the server to later re-render those things based on new edits without the need for sanitization of the options being sent back by the browser, provided the option set was blessed in this manner.
# sortedDistinct(property, cursor, callback)
Fetch the distinct values for the specified property via the specified
cursor and sort them before delivering them to the callback as the
second argument. Like toDistinct
, but sorted. A convenience used
by the standard filters for many field types.
# cursorFilterInterested(cursor, name)
For most cursor filters, if the value is undefined or null, the filter should do nothing. This method implements that test.
# afterInit()
Validate schemas. We wait this long so that we can know if
withType
and friends make sense
# validate(schema, options)
Validate a schema for errors. This is about validating the schema itself, not a data object. For instance, a field without a type property is flagged. Serious errors throw an exception, while certain lesser errors just print a message to stderr for bc.
This method may also prevent errors by automatically supplying
reasonable values for certain properties, such as the idField
property
of a joinByOne
field, or the label
property of anything.
# validateField(field, options, schema, unarranged)
# getPermissionsFieldNames()
Return all standard field names currently associated with permissions editing, for consistency in arrangeFields, batch permissions schemas, etc.