Because Thing plays such a major role in Knickers development, it deserves its own in-depth documentation.
- Field Configuration
- Field-Level Callbacks
- Thing-Level Callbacks
- Special Relative Handling
- Reserved Words
Field Configuration [back to top]
There are a number of parameters you can specify in the configuration array:
-
type: The Parcel type of your field. Used for
getParcel() as well as validating data passed/loaded into your Thing. Should
include only the part of your class name after "Field_" or "FieldSet_" (e.g.,
"Integer").
-
required: Does this field have to have a value for your Thing
to be valid? May be TRUE, FALSE, or THING_REQUIRED_WHITESPACE_OK if you want
to consider whitespace to be a valid value.
-
default: The default value for this field in new Things. Will be
returned when get() is called on the field and stored with the Thing on store().
-
read_only: Boolean. Do not allow the field to have its value set from outside the Thing.
-
no_store: Boolean. Indicates that Thing should not attempt
to store this field to Storage . Also DataSet
should not attempt to absorb this field into any DataSet that
the Thing is added to. You would use this in the case that you wanted the
field around for additional logic (possibly provided by a get_callback)
or for temporarily holding onto a value that its not represented in Storage .
-
storage_field: The name of this field in Storage if it differs from the name
of the field in your Thing. The storage_field will be mapped to your field name on Thing::load() and mapped back
on Thing::store(). Note that multiple fields cannot have the same storage_field.
-
view_of: This field is a different interpretation of another field's value. It is not meant
to be set or stored and therefore must be read_only. Because it cannot share its storage field with another
field, it must have a get_callback to get its value. Setting a field to view_of ensures that DataSet
will pull up the necessary fields from Storage to populate your field.
-
thing: If your field represents a related Thing, rather than a simple value, specify the Thing
class name here. Include the "Thing_" (e.g., "Thing_Movie").
-
link_thing: If your field requires going through a linking Thing to get its relatives, specify
the linking Thing class name here. Include the "Thing_" (e.g., "Thing_Movie").
-
remote_link_field: If your field represents a related Thing with a one-to-many or many-to-many relationship,
specify the name of the field in the other Thing that represents this Thing's ID. For one-to-many, the "other" thing
is the "many" thing. For many-to-many, it's the linking thing.
-
local_id_field: If your field represents a many-to-one relationship, specify the field in this Thing
that represents the related Thing's ID. Note that you'll also need a field for that related Thing's ID in your Thing.
-
ignore_on_delete: Ignore this relative when deleting this Thing. This will prevent Thing from attempting to
validate whether deleting this Thing will invalidate its relatives.
-
delete_on_delete: Delete this relative when deleting this Thing.
-
*_callback: See the Callbacks section below
Field-Level Callbacks [back to top]
Thing provides callback hooks for nearly everything it does. This makes it immensely flexible but also immensely confusing. Below are listed the callbacks, when they are called, what they are sent, and what you are expected to send back from them.
-
load_callback:
- Specified: In $loadCallbacks array, indexed by storage field name.
- Called When: Thing data is loaded from Storage .
- Sent: storage value, field name
- Returns: array, indexed by Thing field name, of values
- Example:
var $fields = array ( 'BIT_ONE_ON' => array ( 'type' => 'Boolean' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean' ) ); var $loadCallbacks = array('MY_STORAGE_FIELD' => 'myLoadCallback'); /** * Populates two fields based on the value of MY_STORAGE_FIELD * *@access private *@param mixed *@param string *@return array */ function myLoadCallback($value, $field) { $returnArray['BIT_ZERO_ON'] = ($value & 1 ? TRUE : FALSE); $returnArray['BIT_ONE_ON'] = ($value & 2 ? TRUE : FALSE); return $returnArray; }
-
storage_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: Thing data is stored to Storage , if your field has had a value set since last store(). Also called when class attempts to determine the storage_field for your field.
- Sent: value, field name
- Returns: array containing storage field name in 'field' index and storage field value in 'value' index.
- Example:
var $fields = array ( 'BIT_ONE_ON' => array ( 'type' => 'Boolean', 'storage_callback' => 'myStorageCallback' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean', 'storage_callback' => 'myStorageCallback' ) ); var $loadCallbacks = array('MY_STORAGE_FIELD' => 'myLoadCallback'); /** * Sets up storage for MY_STORAGE_FIELD * *@access private *@param mixed *@param string *@return array */ function myStorageCallback($value, $field) { $returnArray['field'] = 'MY_STORAGE_FIELD'; $returnArray['value'] = ($this->get('BIT_ZERO_ON') ? 1 : 0); $returnArray['value'] |= ($this->get('BIT_ONE_ON') ? 2 : 0); return $returnArray; }
-
set_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: Field is set() or setFromParcel(). NOT when setInternal().
- Sent: value, field name
- Returns: void
- Example:
var $fields = array ( 'MY_INT' => array ( 'type' => 'Integer' ), 'BIT_ONE_ON' => array ( 'type' => 'Boolean', 'set_callback' => 'mySetCallback' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean', 'set_callback' => 'mySetCallback' ) ); /** * Updates my integer representation of my bits whenever my bits are set * *@access private *@param boolean *@param string *@return void */ function mySetCallback($value, $field) { if($field == 'BIT_ZERO_ON') { if($value) $this->setInternal('MY_INT', $this->get('MY_INT') | 1); else // turn off $this->setInternal('MY_INT', $this->get('MY_INT') & ~1); } else // BIT_ONE_ON { if($value) $this->setInternal('MY_INT', $this->get('MY_INT') | 2); else // turn off $this->setInternal('MY_INT', $this->get('MY_INT') & ~2); } }
-
get_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: Field's value/related Thing is gotten with get() or getParcel().
- Sent: field name, isNew (for getting new related Things), id (for getting existing related Things)
- Returns: value/related Thing (by reference!)
- Example:
var $fields = array ( 'MY_INT' => array ( 'type' => 'Integer' ), 'BIT_ONE_ON' => array ( 'type' => 'Boolean', 'get_callback' => 'myGetCallback' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean', 'get_callback' => 'myGetCallback' ) ); /** * Figures out my bits based on the integer representation * *@access private *@param string *@return boolean */ function &myGetCallback($field) { if($field == 'BIT_ZERO_ON') return ($this->get('MY_INT') & 1 ? TRUE : FALSE); else // BIT_ONE_ON return ($this->get('MY_INT') & 2 ? TRUE : FALSE); }
-
filter_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: Thing::loadByFilter() is called, or results for a DataSet using this Thing are loaded, and filters were set in for this field.
- Sent: Filter
- Returns: Filter or FilterSet
- Example:
var $fields = array ( 'BIT_ONE_ON' => array ( 'type' => 'Boolean', 'filter_callback' => 'myFilterCallback' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean', 'filter_callback' => 'myFilterCallback' ) ); /** * Figures out how to filter my integer based on bit fields * *@access private *@param Filter *@return Filter */ function myFilterCallback($filter) { if($filter->getFieldName() == 'BIT_ZERO_ON') $compareVal = 1; else $compareVal = 2; if($filter->getOperator() == '=') { if($filter->getValue()) // want it to be true return new Filter('MY_INT', '&', $compareVal); else return new Filter('MY_INT', '!&', $compareVal); } else // assuming !=, but in the real world you'd want to be more robust than that { if($filter->getValue()) // want it to be false return new Filter('MY_INT', '!&', $compareVal); else return new Filter('MY_INT', '&', $compareVal); } }
-
sort_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: Thing::loadByFilter() is called, or results for a DataSet using this Thing are loaded, and sorts were set in for this field.
- Sent: Sort
- Returns: Sort or SortSet
- Example:
var $fields = array ( 'BIT_ONE_ON' => array ( 'type' => 'Boolean', 'sort_callback' => 'mySortCallback' ), 'BIT_ZERO_ON' => array ( 'type' => 'Boolean', 'sort_callback' => 'mySortCallback' ) ); /** * Figures out how to sort my integer based on bit fields * *@access private *@param Sort *@return Sort */ function mySortCallback($sort) { if($($->getFieldName() == 'BIT_ZERO_ON') $compareVal = 1; else $compareVal = 2; return new Sort("(BITS & ".$compareVal.')', $sort->getSortOrder()); }
-
parcel_creation_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: A Parcel is created by getParcel. This function exists in your Thing.
- Sent: The Parcel
- Returns: The Parcel
- Example:
var $fields = array ( 'PASSWORD' => array ( 'type' => 'MyPassword', 'parcel_creation_callback' => 'setPasswordEncryptionKey' ) ); /** * Sets our encryption key for password * *@access private *@param Field_MyPassword *@return Field_MyPassword */ function &setPasswordEncryptionKey(&$parcel) { $parcel->setEncryptionKey($this->getID()); return $parcel; }
-
create_parcel_callbacks:
- Specified: In $fields array, in array for field you want it called on. Is an array itself, so that you may have more than one. Array should be indexed by function name, with values the parameter to be passed to the function.
- Called When: A The Parcel is created by getParcel. This function exists in the Parcel .
- Sent: Value from your array
- Returns: Void
- Example:
var $fields = array ( 'NAME' => array ( 'type' => 'Text', 'create_parcel_callbacks' => array ( 'setMaxLength' => 50 ) ) );
-
link_creation_callback:
- Specified: In $fields array, in array for field you want it called on.
- Called When: A related many-to-many Thing is stored.
- Sent: Instance of linking Thing
- Returns: Instance of linking Thing
- Example:
???
Thing-Level Callbacks [back to top]
In addition to functions that are executed based on certain things happening to field data, Thing provides functions that are executed based on what's happening to the Thing overall.
-
setAdditionalAttribs:
- Purpose: Setting up your Thing based on some extra information from the outside world.
- Called When: A Thing is instantiated. Your additional attributes, a FIELDSET , must be passed to the function you are using to create/load Things.
- Sent: additionalAttribs
- Returns: void
-
getAdditionalAttribs:
- Purpose: Pass to the outside world the additional attributes that pertain to this particular Thing.
- Called When: When something outside the Thing calls it.
- Sent: void
- Returns: A FIELDSET
-
preValidateAction:
- Purpose: Execute some action prior to the Thing being validated.
- Called When: Just prior to standard Thing validation. Will be called each time isValid() is called, so if you want it to execute only once, use $this->isValidated to determine if you should run.
- Sent: void
- Returns: void
-
customValidate:
- Purpose: To do additional validation on your Thing fields.
- Called When: After standard Thing field and relative validation is complete. To add an error, simply call addErrorForField($field, $err). Just calling this function will tell your Thing it's not valid. You can use getErrorsForField($field) to determine if a field already has errors.
- Sent: void
- Returns: void
-
customValidateForUpdateMultiple:
- Purpose: To do additional validation on your Thing fields when you're doing a mass update. (Not sure how much this works at this point).
- Called When: After standard Thing field and relative validation is complete and in updateMultiple mode. The idea here is that you're checking to ensure that the field(s) being updated has no dependencies on other fields that are not being updated.
- Sent: void
- Returns: void
-
preCreateAction:
- Purpose: To execute some action prior to creating a new Thing.
- Called When: Just before a new Thing is stored, although after its many-to-one relatives are stored.
- Sent: void
- Returns: void
-
preUpdateAction:
- Purpose: To execute some action prior to updating an existing Thing.
- Called When: Just before an existing Thing is stored, although after its many-to-one relatives are stored.
- Sent: void
- Returns: void
-
postCreateAction:
- Purpose: To execute some action after creating a new Thing.
- Called When: Just after a new Thing is stored, but prior to the storage of any one-to-one, one-to-many, or many-to-many relatives.
- Sent: void
- Returns: void
-
postUpdateAction:
- Purpose: To execute some action after updating an existing Thing.
- Called When: Just after an existing Thing is stored, but prior to the storage of any one-to-one, one-to-many, or many-to-many relatives. This function is called even if no fields in the Thing have changed value.
- Sent: void
- Returns: void
-
postDeleteAction:
- Purpose: To execute some action after deleting a Thing.
- Called When: After the Thing and any relatives configured to be deleted when it's deleted are removed from storage.
- Sent: void
- Returns: void
Special Relative Handling [back to top]
Sometimes your Thing needs to deal with its relatives in a more customized fashion. If you do so, there are some things you should know.
-
get_callbacks: If you use a getCallback to pull up your relatives, you should be aware of:
- isNew: The second parameter to your callback will be a boolean indicating if get() is looking for a new relative (rather than an existing one). You can use this to determine if you should send back a new related Thing.
- id: The third parameter to your callback will be an ID indicating if get() is looking for a particular relative. You can use this to determine if you should send back all relatives or just the one it wants.
- connect(): After you've created/loaded your related Thing, if it's a single Thing, you'll want to call $yourThing->connect($field, $relative) to make sure your original thing is properly aware of its relative(s).
- setCreator(): If your callback pulls up an Iterator of relatives, you'll want to call $iterator->setCreator($field, $this) to make the relatives properly aware of your Thing.
-
setByRef: Takes its value by reference, so that you may set in your related Thing(s) and keep them around. get() can then return the
same object that was set() in, rather than re-creating a new one.
Reserved Words [back to top]
Certain words are reserved for Thing's interaction with other objects. These include:
-
ID: Retrieves the Thing's ID (same as calling getID()). If you want this to work with getParcel() you'll want to set your $idFieldType var.
-
IS_NEW: Boolean that indicates if the Thing is new (same as calling isNew()).
-
DELETE: Boolean that indicates if a Thing should be deleted. Mostly used in conjunction with Delete components on interfaces.