getInputType(); $outputType =& $this->getOutputType(); if (is_a($inputType, 'MetadataTypeDescription')) { // We are in meta-data injection mode (or both input and output are meta-data descriptions). $metadataTypeDescription =& $inputType; /* @var $metadataTypeDescription MetadataTypeDescription */ assert(is_a($outputType, 'ClassTypeDescription')); $dataObjectTypeDescription =& $outputType; /* @var $dataObjectTypeDescription ClassTypeDescription */ } else { // We are in meta-data extraction mode. assert(is_a($outputType, 'MetadataTypeDescription')); $metadataTypeDescription =& $outputType; assert(is_a($inputType, 'ClassTypeDescription')); $dataObjectTypeDescription =& $inputType; } // Extract information from the input/output types. $this->_metadataSchemaName = $metadataTypeDescription->getMetadataSchemaClass(); $this->_assocType = $metadataTypeDescription->getAssocType(); $this->_dataObjectName = $dataObjectTypeDescription->getTypeName(); // Set the display name. if (is_a($inputType, 'MetadataTypeDescription')) { $this->setDisplayName('Inject metadata into a(n) '.$this->getDataObjectClass()); } else { $this->setDisplayName('Extract metadata from a(n) '.$this->getDataObjectClass()); } } // // Getters and setters // /** * Get the fully qualified class name of * the supported meta-data schema. * @return string */ function getMetadataSchemaName() { return $this->_metadataSchemaName; } /** * Get the supported meta-data schema (lazy load) * @return MetadataSchema */ function &getMetadataSchema() { // Lazy-load the meta-data schema if this has // not been done before. if (is_null($this->_metadataSchema)) { $metadataSchemaName = $this->getMetadataSchemaName(); assert(!is_null($metadataSchemaName)); $this->_metadataSchema =& instantiate($metadataSchemaName, 'MetadataSchema'); assert(is_object($this->_metadataSchema)); } return $this->_metadataSchema; } /** * Convenience method that returns the * meta-data name space. * @return string */ function getMetadataNamespace() { $metadataSchema =& $this->getMetadataSchema(); return $metadataSchema->getNamespace(); } /** * Get the supported application entity (class) name * @return string */ function getDataObjectName() { return $this->_dataObjectName; } /** * Return the data object class name * (without the package prefix) * * @return string */ function getDataObjectClass() { if (is_null($this->_dataObjectClass)) { $dataObjectName = $this->getDataObjectName(); assert(!is_null($dataObjectName)); $dataObjectNameParts = explode('.', $dataObjectName); $this->_dataObjectClass = array_pop($dataObjectNameParts); } return $this->_dataObjectClass; } /** * Get the association type corresponding to the data * object type. * @return integer */ function getAssocType() { return $this->_assocType; } /** * Set the target data object for meta-data injection. * @param $targetDataObject DataObject */ function setTargetDataObject(&$targetDataObject) { $this->_targetDataObject =& $targetDataObject; } /** * Get the target data object for meta-data injection. * @param $targetDataObject DataObject */ function &getTargetDataObject() { return $this->_targetDataObject; } // // Abstract template methods // /** * Inject a MetadataDescription into the target DataObject * @param $metadataDescription MetadataDescription * @param $targetDataObject DataObject * @return DataObject */ function &injectMetadataIntoDataObject(&$metadataDescription, &$targetDataObject) { // Must be implemented by sub-classes assert(false); } /** * Extract a MetadataDescription from a source DataObject. * @param $sourceDataObject DataObject * @return MetadataDescription */ function &extractMetadataFromDataObject(&$sourceDataObject) { // Must be implemented by sub-classes assert(false); } /** * Return the additional field names introduced by the * meta-data schema that need to be persisted in the * ..._settings table corresponding to the DataObject * which is supported by this adapter. * NB: The field names must be prefixed with the meta-data * schema namespace identifier. * @param $translated boolean if true, return localized field * names, otherwise return additional field names. * @return array an array of field names to be persisted. */ function getDataObjectMetadataFieldNames($translated = true) { // By default return all field names return $this->getMetadataFieldNames($translated); } // // Implement template methods from Filter // /** * Convert a MetadataDescription to an application * object or vice versa. * @see Filter::process() * @param $input mixed either a MetadataDescription or an application object * @return mixed either a MetadataDescription or an application object */ function &process(&$input) { // Do we inject or extract metadata? switch (true) { case is_a($input, 'MetadataDescription'): $targetDataObject =& $this->getTargetDataObject(); // Instantiate a new data object if none was given. if (is_null($targetDataObject)) { $targetDataObject =& $this->instantiateDataObject(); assert(is_a($targetDataObject, $this->getDataObjectName())); } // Inject meta-data into the data object. $output =& $this->injectMetadataIntoDataObject($input, $targetDataObject); break; case is_a($input, $this->getDataObjectClass()): $output =& $this->extractMetadataFromDataObject($input); break; default: // Input should be validated by now. assert(false); } return $output; } // // Protected helper methods // /** * Instantiate a new data object of the * correct type. * * NB: This can be overridden by sub-classes for more complex * data objects. The standard implementation assumes there are * no constructor args to be set or configurations to be made. * * @return DataObject */ function &instantiateDataObject() { $dataObjectName = $this->getDataObjectName(); assert(!is_null($dataObjectName)); $dataObject =& instantiate($dataObjectName, $this->getDataObjectClass()); return $dataObject; } /** * Instantiate a meta-data description that conforms to the * settings of this adapter. * @return MetadataDescription */ function &instantiateMetadataDescription() { $metadataDescription = new MetadataDescription($this->getMetadataSchemaName(), $this->getAssocType()); return $metadataDescription; } /** * Return all field names introduced by the * meta-data schema that might have to be persisted. * @param $translated boolean if true, return localized field * names, otherwise return additional field names. * @return array an array of field names to be persisted. */ function getMetadataFieldNames($translated = true) { // Do we need to build the field name cache first? if (is_null($this->_metadataFieldNames)) { // Initialize the cache array $this->_metadataFieldNames = array(); // Retrieve all properties and add // their names to the cache $metadataSchema =& $this->getMetadataSchema(); $metadataSchemaNamespace = $metadataSchema->getNamespace(); $properties =& $metadataSchema->getProperties(); foreach($properties as $property) { $propertyAssocTypes = $property->getAssocTypes(); if (in_array($this->_assocType, $propertyAssocTypes)) { // Separate translated and non-translated property names // and add the name space so that field names are unique // across various meta-data schemas. $this->_metadataFieldNames[$property->getTranslated()][] = $metadataSchemaNamespace.':'.$property->getName(); } } } // Return the field names return $this->_metadataFieldNames[$translated]; } /** * Set several localized statements in a meta-data schema. * @param $metadataDescription MetadataDescription * @param $propertyName string * @param $localizedValues array (keys: locale, values: localized values) */ function addLocalizedStatements(&$metadataDescription, $propertyName, $localizedValues) { if (is_array($localizedValues)) { foreach ($localizedValues as $locale => $values) { // Handle cardinality "many" and "one" in the same way. if (is_scalar($values)) $values = array($values); foreach($values as $value) { $metadataDescription->addStatement($propertyName, $value, $locale); unset($value); } } } } /** * Directly inject all fields that are not mapped to the * data object into the data object's data array for * automatic persistence by the meta-data framework. * @param $metadataDescription MetadataDescription * @param $dataObject DataObject */ function injectUnmappedDataObjectMetadataFields(&$metadataDescription, &$dataObject) { // Handle translated and non-translated statements separately. foreach(array(true, false) as $translated) { // Retrieve the unmapped fields. foreach($this->getDataObjectMetadataFieldNames($translated) as $unmappedProperty) { // Identify the corresponding property name. list($namespace, $propertyName) = explode(':', $unmappedProperty); // Find out whether we have a statement for this unmapped property. if ($metadataDescription->hasStatement($propertyName)) { // Add the unmapped statement directly to the // data object. if ($translated) { $dataObject->setData($unmappedProperty, $metadataDescription->getStatementTranslations($propertyName)); } else { $dataObject->setData($unmappedProperty, $metadataDescription->getStatement($propertyName)); } } } } } /** * Directly extract all fields that are not mapped to the * data object from the data object's data array. * @param $dataObject DataObject * @param $metadataDescription MetadataDescription */ function extractUnmappedDataObjectMetadataFields(&$dataObject, &$metadataDescription) { $metadataSchema =& $this->getMetadataSchema(); $handledNamespace = $metadataSchema->getNamespace(); // Handle translated and non-translated statements separately. foreach(array(true, false) as $translated) { // Retrieve the unmapped fields. foreach($this->getDataObjectMetadataFieldNames($translated) as $unmappedProperty) { // Find out whether we have a statement for this unmapped property. if ($dataObject->hasData($unmappedProperty)) { // Identify the corresponding property name and namespace. list($namespace, $propertyName) = explode(':', $unmappedProperty); // Only extract data if the namespace of the property // is the same as the one handled by this adapter and the // property is within the current description. if ($namespace == $handledNamespace && $metadataSchema->hasProperty($propertyName)) { // Add the unmapped statement to the metadata description. if ($translated) { $this->addLocalizedStatements($metadataDescription, $propertyName, $dataObject->getData($unmappedProperty)); } else { $metadataDescription->addStatement($propertyName, $dataObject->getData($unmappedProperty)); } } } } } } } ?>