/**
  *	Recursively return the relationships for a given data object map.
  */
 private function recursiveRelationships(&$object, $attributeVisibility = false, $cache = array())
 {
     $output = array();
     // Cache relationship data objects to prevent infinite recursion.
     if (!in_array("{$object['ClassName']} {$object['ID']}", $cache)) {
         $cache[] = "{$object['ClassName']} {$object['ID']}";
         foreach ($object as $attribute => $value) {
             if ($attribute !== 'ClassName' && $attribute !== 'RecordClassName') {
                 // Grab the name of a relationship.
                 $relationship = substr($attribute, strlen($attribute) - 2) === 'ID' && strlen($attribute) > 2 ? substr($attribute, 0, -2) : null;
                 if ($relationship && ($relationObject = DataObject::get_by_id($object['ClassName'], $object['ID'])) && $relationObject->hasMethod($relationship) && $value != 0) {
                     // Grab the relationship.
                     $relationObject = $relationObject->{$relationship}();
                     // Make sure recursive relationships are enabled.
                     if (!$this->recursiveRelationships) {
                         $output[$relationship] = array($relationObject->ClassName => array('ID' => (string) $relationObject->ID));
                         continue;
                     }
                     $temporaryMap = $relationObject->toMap();
                     if ($attributeVisibility) {
                         // Grab the attribute visibility.
                         $class = is_subclass_of($relationObject->ClassName, 'SiteTree') ? 'SiteTree' : (is_subclass_of($relationObject->ClassName, 'File') ? 'File' : $relationObject->ClassName);
                         $relationConfiguration = DataObjectOutputConfiguration::get_one('DataObjectOutputConfiguration', "IsFor = '" . Convert::raw2sql($class) . "'");
                         $relationVisibility = $relationConfiguration && $relationConfiguration->APIwesomeVisibility ? explode(',', $relationConfiguration->APIwesomeVisibility) : null;
                         $columns = array();
                         foreach (ClassInfo::subclassesFor($class) as $subclass) {
                             // Prepend the table names.
                             $subclassColumns = array();
                             foreach (DataObject::database_fields($subclass) as $column => $type) {
                                 $subclassColumns["{$subclass}.{$column}"] = $type;
                             }
                             $columns = array_merge($columns, $subclassColumns);
                         }
                         array_shift($columns);
                         // Make sure this relationship has visibility customisation.
                         if (is_null($relationVisibility) || count($relationVisibility) !== count($columns) || !in_array('1', $relationVisibility)) {
                             $output[$relationship] = array($relationObject->ClassName => array('ID' => (string) $relationObject->ID));
                             continue;
                         }
                         // Grab all data object visible attributes.
                         $select = array('ClassName' => $relationObject->ClassName, 'ID' => $relationObject->ID);
                         $iteration = 0;
                         foreach ($columns as $relationshipAttribute => $relationshipType) {
                             if (isset($relationVisibility[$iteration]) && $relationVisibility[$iteration]) {
                                 $split = explode('.', $relationshipAttribute);
                                 $relationshipAttribute = count($split) === 2 ? $split[1] : $relationshipAttribute;
                                 if (isset($temporaryMap[$relationshipAttribute]) && $temporaryMap[$relationshipAttribute]) {
                                     // Retrieve the relationship value, and compose any asset file paths.
                                     $relationshipValue = $temporaryMap[$relationshipAttribute];
                                     $select[$relationshipAttribute] = (strpos(strtolower($relationshipAttribute), 'file') !== false || strpos(strtolower($relationshipAttribute), 'image') !== false) && strpos($relationshipValue, 'assets/') !== false ? Director::absoluteURL($relationshipValue) : (is_integer($relationshipValue) ? (string) $relationshipValue : $relationshipValue);
                                 }
                             }
                             $iteration++;
                         }
                     } else {
                         $select = $temporaryMap;
                     }
                     // Check the corresponding relationship.
                     $output[$relationship] = array($relationObject->ClassName => $this->recursiveRelationships($select, $attributeVisibility, $cache));
                 } else {
                     // Compose any asset file paths.
                     $output[$attribute] = (strpos(strtolower($attribute), 'file') !== false || strpos(strtolower($attribute), 'image') !== false) && strpos($value, 'assets/') !== false ? Director::absoluteURL($value) : (is_integer($value) ? (string) $value : $value);
                 }
             }
         }
     } else {
         // This relationship has previously been cached.
         $output['ID'] = $object['ID'];
     }
     // Return the visible relationship attributes.
     return $output;
 }
 /**
  *	Add an output configuration for a new data object.
  */
 private function addConfiguration($object)
 {
     // Create a new output configuration.
     $configuration = DataObjectOutputConfiguration::create();
     // Assign the data object against this configuration.
     $configuration->IsFor = $object;
     $configuration->write();
     DB::alteration_message($object . ' JSON/XML Configuration', 'created');
 }