danielebarchiesi@4: formatName = $name; danielebarchiesi@4: $this->formatInfo = $info; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Gets the representation of a resource. danielebarchiesi@4: */ danielebarchiesi@4: public function viewResource($resourceController, $id) { danielebarchiesi@4: $values = self::getData($resourceController->wrapper($id)); danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $values, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $this->serialize($values); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Creates a new resource. danielebarchiesi@4: */ danielebarchiesi@4: public function createResource($resourceController, $data) { danielebarchiesi@4: $values = $this->unserialize($resourceController->propertyInfo(), $data); danielebarchiesi@4: $id = $resourceController->create($values); danielebarchiesi@4: $ref = self::getResourceReference($resourceController->resource(), $id); danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $ref, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $this->serialize($ref); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Updates a resource. danielebarchiesi@4: */ danielebarchiesi@4: public function updateResource($resourceController, $id, $data) { danielebarchiesi@4: $values = $this->unserialize($resourceController->propertyInfo(), $data); danielebarchiesi@4: $resourceController->update($id, $values); danielebarchiesi@4: // Return an empty representation by default. danielebarchiesi@4: $value = array(); danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $value, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $this->serialize($value); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Deletes a resource. danielebarchiesi@4: */ danielebarchiesi@4: public function deleteResource($resourceController, $id) { danielebarchiesi@4: $resourceController->delete($id); danielebarchiesi@4: // Return an empty representation by default. danielebarchiesi@4: $value = array(); danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $value, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $this->serialize($value); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Implements RestWSFormatInterface::queryResource(). danielebarchiesi@4: */ danielebarchiesi@4: public function queryResource($resourceController, $payload) { danielebarchiesi@4: // Get the parameter from the URL. danielebarchiesi@4: $parameters = drupal_get_query_parameters(); danielebarchiesi@4: danielebarchiesi@4: $rest_controls = restws_meta_controls(); danielebarchiesi@4: $properties = $resourceController->propertyInfo(); danielebarchiesi@4: $split_parameters = $this->splitParameters($properties, $parameters); danielebarchiesi@4: danielebarchiesi@4: $values = $this->generateQueryURIs($resourceController, $parameters, $split_parameters['filters']); danielebarchiesi@4: danielebarchiesi@4: $full = (isset($split_parameters['meta_controls'][$rest_controls['full']])) ? $split_parameters['meta_controls'][$rest_controls['full']] : 1; danielebarchiesi@4: danielebarchiesi@4: $result = $resourceController->query($split_parameters['filters'], $split_parameters['meta_controls']); danielebarchiesi@4: if ($full === '0') { danielebarchiesi@4: foreach ($result as $id) { danielebarchiesi@4: $values['list'][] = $this->getResourceReference($resourceController->resource(), $id); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: foreach ($result as $id) { danielebarchiesi@4: $values['list'][] = self::getData($resourceController->wrapper($id)); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $values, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $this->serialize($values); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function mimeType() { danielebarchiesi@4: return $this->formatInfo['mime type']; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function getName() { danielebarchiesi@4: return $this->formatName; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Gets a simple PHP array using URI references for some wrapped data. danielebarchiesi@4: * danielebarchiesi@4: * This is the counter-part of self::getPropertyValues(). danielebarchiesi@4: */ danielebarchiesi@4: public static function getData($wrapper) { danielebarchiesi@4: $data = array(); danielebarchiesi@4: $filtered = restws_property_access_filter($wrapper); danielebarchiesi@4: foreach ($filtered as $name => $property) { danielebarchiesi@4: try { danielebarchiesi@4: if ($property instanceof EntityDrupalWrapper) { danielebarchiesi@4: // For referenced entities only return the URI. danielebarchiesi@4: if ($id = $property->getIdentifier()) { danielebarchiesi@4: $data[$name] = self::getResourceReference($property->type(), $id); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityValueWrapper) { danielebarchiesi@4: $data[$name] = $property->value(); danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) { danielebarchiesi@4: $data[$name] = self::getData($property); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: catch (EntityMetadataWrapperException $e) { danielebarchiesi@4: // A property causes problems - ignore that. danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return $data; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public static function getResourceReference($resource, $id) { danielebarchiesi@4: $return = array( danielebarchiesi@4: 'uri' => restws_resource_uri($resource, $id), danielebarchiesi@4: 'id' => $id, danielebarchiesi@4: 'resource' => $resource, danielebarchiesi@4: ); danielebarchiesi@4: if (module_exists('uuid') && entity_get_info($resource)) { danielebarchiesi@4: $ids = entity_get_uuid_by_id($resource, array($id)); danielebarchiesi@4: if ($id = reset($ids)) { danielebarchiesi@4: $return['uuid'] = $id; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return $return; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Transforms simple-array data values to valid entity property values. danielebarchiesi@4: * danielebarchiesi@4: * This is the counter-part of self::getData(), thus it converts resource danielebarchiesi@4: * references to the required value(s). danielebarchiesi@4: * danielebarchiesi@4: * @param array $values danielebarchiesi@4: * The array representation of the data values. danielebarchiesi@4: * @param $property_info danielebarchiesi@4: * The property info array of the entity type for which we are transforming danielebarchiesi@4: * the values. danielebarchiesi@4: */ danielebarchiesi@4: protected function getPropertyValues(array &$values, $property_info) { danielebarchiesi@4: foreach ($values as $name => &$property_value) { danielebarchiesi@4: if (isset($property_info[$name]) && $info = $property_info[$name]) { danielebarchiesi@4: danielebarchiesi@4: // Check if there is a resource array and if the property has a type. danielebarchiesi@4: if (is_array($property_value) && isset($info['type'])) { danielebarchiesi@4: danielebarchiesi@4: // Check if the field is a list or a single value field. danielebarchiesi@4: if (entity_property_list_extract_type($info['type'])) { danielebarchiesi@4: // Check if the list values consist of structure wrappers. danielebarchiesi@4: if (array_key_exists('property info', $info)) { danielebarchiesi@4: foreach ($property_value as &$list_values) { danielebarchiesi@4: $this->getPropertyValues($list_values, $info['property info']); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $list_type = entity_property_list_extract_type($info['type']); danielebarchiesi@4: foreach ($property_value as &$list_value) { danielebarchiesi@4: $list_value = $this->getResourceReferenceValue($list_type, $list_value); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: // Check if the property is a structure wrapper. danielebarchiesi@4: if (array_key_exists('property info', $info)) { danielebarchiesi@4: $this->getPropertyValues($property_value, $info['property info']); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $property_value = $this->getResourceReferenceValue($info['type'], $property_value); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Gets the resource reference value. danielebarchiesi@4: * danielebarchiesi@4: * @param $type danielebarchiesi@4: * The data type of the reference property. danielebarchiesi@4: * @param array $reference danielebarchiesi@4: * The input data specifying the resource reference in one supported way. danielebarchiesi@4: * danielebarchiesi@4: * @return mixed danielebarchiesi@4: * The value to be set for the reference. Usually this is an entity or danielebarchiesi@4: * resource id, but for generic entity references it's an danielebarchiesi@4: * EntityDrupalWrapper. danielebarchiesi@4: * danielebarchiesi@4: * @see RestWSBaseFormat::getResourceReference() danielebarchiesi@4: */ danielebarchiesi@4: protected function getResourceReferenceValue($type, array $reference) { danielebarchiesi@4: danielebarchiesi@4: if (isset($reference['id']) && $type != 'entity') { danielebarchiesi@4: return $reference['id']; danielebarchiesi@4: } danielebarchiesi@4: // Handle setting generic entity references, i.e. of type entity. danielebarchiesi@4: elseif ($type == 'entity' && isset($reference['id']) && isset($reference['resource'])) { danielebarchiesi@4: if (!entity_get_info($reference['resource'])) { danielebarchiesi@4: throw new RestWSException('Invalid resource for entity reference given.', 406); danielebarchiesi@4: } danielebarchiesi@4: return entity_metadata_wrapper($reference['resource'], $reference['id']); danielebarchiesi@4: } danielebarchiesi@4: elseif (isset($reference['uri'])) { danielebarchiesi@4: // @todo: Implement setting references by URI by parsing resource/id from danielebarchiesi@4: // the URI. danielebarchiesi@4: } danielebarchiesi@4: elseif (isset($reference['uuid']) && module_exists('uuid') && $type != 'entity') { danielebarchiesi@4: $ids = entity_get_id_by_uuid($type, array($reference['uuid'])); danielebarchiesi@4: if (!$ids) { danielebarchiesi@4: throw new RestWSException('Invalid UUID for resource reference given.', 406); danielebarchiesi@4: } danielebarchiesi@4: return reset($ids); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: throw new RestWSException('Invalid value for resource reference given.', 406); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Splits a query parameter into two sub arrays containing the filters and danielebarchiesi@4: * meta controls. danielebarchiesi@4: * danielebarchiesi@4: * @param array $properties danielebarchiesi@4: * An array containing the properties of the resource. danielebarchiesi@4: * danielebarchiesi@4: * @param array $parameters danielebarchiesi@4: * An array which contains filters and meta controls. danielebarchiesi@4: * danielebarchiesi@4: * @return array danielebarchiesi@4: * An array containing two sub arrays, one for filters and one for meta danielebarchiesi@4: * controls with corresponding keys. danielebarchiesi@4: * danielebarchiesi@4: * @throws RestWSException danielebarchiesi@4: * If a filter isn't valid, the function will throw a RestWSException with danielebarchiesi@4: * the 412 HTTP status code. danielebarchiesi@4: */ danielebarchiesi@4: protected function splitParameters($properties, array $parameters) { danielebarchiesi@4: $meta_controls = array(); danielebarchiesi@4: $rest_controls = restws_meta_controls(); danielebarchiesi@4: foreach ($parameters as $control_name => $property) { danielebarchiesi@4: if (isset($rest_controls[$control_name])) { danielebarchiesi@4: $meta_controls[$control_name] = $property; danielebarchiesi@4: unset($parameters[$control_name]); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $filters = array(); danielebarchiesi@4: foreach ($parameters as $parameter => $value) { danielebarchiesi@4: // Check if the property is prefixed. danielebarchiesi@4: if (substr($parameter, 0, 9) == 'property_') { danielebarchiesi@4: $parameter = substr($parameter, 9, strlen($parameter) - 9); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // If the parameter doesn't exist, we can not filter for and need to danielebarchiesi@4: // notify the client about it. danielebarchiesi@4: if (!isset($properties[$parameter])) { danielebarchiesi@4: throw new RestWSException('Not a valid filter: ' . $parameter, 412); danielebarchiesi@4: } danielebarchiesi@4: $filters[$parameter] = $value; danielebarchiesi@4: } danielebarchiesi@4: return array('meta_controls' => $meta_controls, 'filters' => $filters); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Generates all navigation links for querying. danielebarchiesi@4: * danielebarchiesi@4: * @param RestWSResourceControllerInterface $resourceController danielebarchiesi@4: * The controller used to query the resource. danielebarchiesi@4: * danielebarchiesi@4: * @param array $parameters danielebarchiesi@4: * The HTTP GET parameters for the query. danielebarchiesi@4: * danielebarchiesi@4: * @param array $filters danielebarchiesi@4: * The filters for the query. danielebarchiesi@4: * danielebarchiesi@4: * @return array danielebarchiesi@4: * An array containing all navigation links. danielebarchiesi@4: * danielebarchiesi@4: * @throws RestWSException danielebarchiesi@4: * If the page is out of range the function will throw a new RestWSException danielebarchiesi@4: * with HTTP status code 404. danielebarchiesi@4: */ danielebarchiesi@4: protected function generateQueryURIs(RestWSResourceControllerInterface $resourceController, array $parameters, array $filters) { danielebarchiesi@4: $rest_controls = restws_meta_controls(); danielebarchiesi@4: danielebarchiesi@4: $count = $resourceController->count($filters); danielebarchiesi@4: $limit = isset($parameters[$rest_controls['limit']]) ? $parameters[$rest_controls['limit']] : NULL; danielebarchiesi@4: $limit = $resourceController->limit($limit); danielebarchiesi@4: $page = isset($parameters[$rest_controls['page']]) ? $parameters[$rest_controls['page']] : 0; danielebarchiesi@4: danielebarchiesi@4: $last = ceil($count / $limit) - 1; danielebarchiesi@4: danielebarchiesi@4: if ($page > $last || $page < 0) { danielebarchiesi@4: throw new RestWSException('Page doesn\'t exist.', 404); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $uris = array(); danielebarchiesi@4: $options = array( danielebarchiesi@4: 'query' => &$parameters, danielebarchiesi@4: ); danielebarchiesi@4: danielebarchiesi@4: $uris['self'] = restws_resource_uri($resourceController->resource(), null, $options); danielebarchiesi@4: $parameters['page'] = 0; danielebarchiesi@4: $uris['first'] = restws_resource_uri($resourceController->resource(), null, $options); danielebarchiesi@4: $parameters['page'] = $last; danielebarchiesi@4: $uris['last'] = restws_resource_uri($resourceController->resource(), null, $options); danielebarchiesi@4: danielebarchiesi@4: danielebarchiesi@4: if ($page != 0) { danielebarchiesi@4: $parameters['page'] = $page - 1; danielebarchiesi@4: $uris['prev'] = restws_resource_uri($resourceController->resource(), null, $options); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: if ($page != $last) { danielebarchiesi@4: $parameters['page'] = $page + 1; danielebarchiesi@4: $uris['next'] = restws_resource_uri($resourceController->resource(), null, $options); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: return $uris; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Filters out properties where view access is not allowed for the current user. danielebarchiesi@4: * danielebarchiesi@4: * @param EntityMetadataWrapper $wrapper danielebarchiesi@4: * EntityMetadataWrapper that should be checked. danielebarchiesi@4: * danielebarchiesi@4: * @return danielebarchiesi@4: * An array of properties where access is allowed, keyed by their property danielebarchiesi@4: * name. danielebarchiesi@4: */ danielebarchiesi@4: function restws_property_access_filter($wrapper) { danielebarchiesi@4: $filtered = array(); danielebarchiesi@4: foreach ($wrapper as $name => $property) { danielebarchiesi@4: if ($property->access('view')) { danielebarchiesi@4: $filtered[$name] = $property; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: return $filtered; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * A formatter to format json. danielebarchiesi@4: */ danielebarchiesi@4: class RestWSFormatJSON extends RestWSBaseFormat { danielebarchiesi@4: danielebarchiesi@4: public function serialize($values) { danielebarchiesi@4: return drupal_json_encode($values); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function unserialize($properties, $data) { danielebarchiesi@4: $values = drupal_json_decode($data); danielebarchiesi@4: $this->getPropertyValues($values, $properties); danielebarchiesi@4: return $values; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * A formatter for XML. danielebarchiesi@4: */ danielebarchiesi@4: class RestWSFormatXML extends RestWSBaseFormat { danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Gets the representation of a resource. danielebarchiesi@4: */ danielebarchiesi@4: public function viewResource($resourceController, $id) { danielebarchiesi@4: $xml = new DOMDocument('1.0', 'utf-8'); danielebarchiesi@4: $element = $xml->createElement($resourceController->resource()); danielebarchiesi@4: self::addToXML($xml, $element, $resourceController->wrapper($id)); danielebarchiesi@4: $xml->appendChild($element); danielebarchiesi@4: danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $xml, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $xml->saveXML(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Creates a new resource. danielebarchiesi@4: */ danielebarchiesi@4: public function createResource($resourceController, $data) { danielebarchiesi@4: $values = $this->unserialize($resourceController->propertyInfo(), $data); danielebarchiesi@4: $id = $resourceController->create($values); danielebarchiesi@4: danielebarchiesi@4: $xml = new DOMDocument('1.0', 'utf-8'); danielebarchiesi@4: $element = $xml->createElement('uri'); danielebarchiesi@4: self::setXMLReference($element, $resourceController->resource(), $id); danielebarchiesi@4: $xml->appendChild($element); danielebarchiesi@4: danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $xml, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $xml->saveXML(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Overrides RestWSBaseFormat::queryResource(). danielebarchiesi@4: */ danielebarchiesi@4: public function queryResource($resourceController, $payload) { danielebarchiesi@4: $xml = new DOMDocument('1.0', 'utf-8'); danielebarchiesi@4: $element = $xml->createElement('list'); danielebarchiesi@4: danielebarchiesi@4: $rest_controls = restws_meta_controls(); danielebarchiesi@4: $parameters = drupal_get_query_parameters(); danielebarchiesi@4: $properties = $resourceController->propertyInfo(); danielebarchiesi@4: $split_parameters = $this->splitParameters($properties, $parameters); danielebarchiesi@4: danielebarchiesi@4: $links = $this->generateQueryURIs($resourceController, $parameters, $split_parameters['filters']); danielebarchiesi@4: danielebarchiesi@4: foreach ($links as $rel => $link) { danielebarchiesi@4: $item = $xml->createElement('link'); danielebarchiesi@4: $item->setAttribute('rel', $rel); danielebarchiesi@4: $item->setAttribute('href', $link); danielebarchiesi@4: $element->appendChild($item); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $full = (isset($split_parameters['meta_controls'][$rest_controls['full']])) ? $split_parameters['meta_controls'][$rest_controls['full']] : 1; danielebarchiesi@4: danielebarchiesi@4: $result = $resourceController->query($split_parameters['filters'], $split_parameters['meta_controls']); danielebarchiesi@4: danielebarchiesi@4: if ($full === '0') { danielebarchiesi@4: foreach ($result as $id) { danielebarchiesi@4: $item = $xml->createElement($resourceController->resource()); danielebarchiesi@4: self::setXMLReference($item, $resourceController->resource(), $id); danielebarchiesi@4: $element->appendChild($item); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: foreach ($result as $id) { danielebarchiesi@4: $item = $xml->createElement($resourceController->resource()); danielebarchiesi@4: self::addToXML($xml, $item, $resourceController->wrapper($id)); danielebarchiesi@4: $element->appendChild($item); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $xml->appendChild($element); danielebarchiesi@4: danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $xml, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $xml->saveXML(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function serialize($data) { danielebarchiesi@4: // Return an empty XML document. danielebarchiesi@4: $xml = new DOMDocument('1.0', 'utf-8'); danielebarchiesi@4: return $xml->saveXML(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function unserialize($properties, $data) { danielebarchiesi@4: $xml = simplexml_load_string($data); danielebarchiesi@4: return $this->xmlToArray($properties, $xml); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Turns the xml structure into an array of values. danielebarchiesi@4: */ danielebarchiesi@4: public function xmlToArray($properties, SimpleXMLElement $xml, $listItemType = NULL) { danielebarchiesi@4: foreach ($xml->children() as $name => $element) { danielebarchiesi@4: // Check if we are processing an entity, an item from a list or a list. danielebarchiesi@4: if ((isset($properties[$name]['type']) && (entity_property_list_extract_type($properties[$name]['type']) || entity_get_info($properties[$name]['type']))) || isset($listItemType)) { danielebarchiesi@4: // If we are processing a list, then set the type of the list and save danielebarchiesi@4: // the results into a a numeric array. danielebarchiesi@4: if (isset($listItemType)) { danielebarchiesi@4: $type = $listItemType; danielebarchiesi@4: $result_pointer = &$result[]; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $type = $properties[$name]['type']; danielebarchiesi@4: $result_pointer = &$result[$name]; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: // Check if the type is a list. danielebarchiesi@4: if (entity_property_list_extract_type($type)) { danielebarchiesi@4: $result_pointer = $this->xmlToArray($properties, $element, entity_property_list_extract_type($type)); danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $attributes = $element->attributes(); danielebarchiesi@4: $values['id'] = (string)$attributes['id']; danielebarchiesi@4: $values['resource'] = (string)$attributes['resource']; danielebarchiesi@4: $values['uri'] = $this->xmlToArray($properties, $element); danielebarchiesi@4: $id = $this->getResourceReferenceValue($type, $values); danielebarchiesi@4: // If an id could be extracted, then a resource array was send. danielebarchiesi@4: if ($id !== FALSE) { danielebarchiesi@4: $result_pointer = $id; danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: // If no ID could be extracted, then save the inner text content of danielebarchiesi@4: // the node, which is saved in the $values['uri']. danielebarchiesi@4: $result_pointer = $values['uri']; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: else { danielebarchiesi@4: $result[$name] = $this->xmlToArray($properties, $element); danielebarchiesi@4: } danielebarchiesi@4: foreach ($xml->attributes() as $attribute_name => $attribute_value) { danielebarchiesi@4: $result[$attribute_name] = $attribute_value; danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: if (!isset($result)) { danielebarchiesi@4: $result = ($string = (string) $xml) ? $string : NULL; danielebarchiesi@4: } danielebarchiesi@4: return $result; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Adds the data of the given wrapper to the given XML element. danielebarchiesi@4: */ danielebarchiesi@4: public static function addToXML(DOMDocument $doc, DOMNode $parent, $wrapper) { danielebarchiesi@4: $filtered = restws_property_access_filter($wrapper); danielebarchiesi@4: foreach ($filtered as $name => $property) { danielebarchiesi@4: try { danielebarchiesi@4: if ($property instanceof EntityDrupalWrapper) { danielebarchiesi@4: // For referenced entities only return the URI. danielebarchiesi@4: if ($id = $property->getIdentifier()) { danielebarchiesi@4: $element = $doc->createElement(is_numeric($name) ? 'item' : $name); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: self::setXMLReference($element, $property->type(), $id); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityValueWrapper) { danielebarchiesi@4: // Only primitive data types are allowed here. There might be complex danielebarchiesi@4: // arrays/objects in EntityValueWrapper if no property information is danielebarchiesi@4: // provided (example: the "data" property of commerce_price fields. danielebarchiesi@4: if (is_scalar($property->value())) { danielebarchiesi@4: $escaped = $doc->createTextNode($property->value()); danielebarchiesi@4: $element = $doc->createElement(is_numeric($name) ? 'item' : $name); danielebarchiesi@4: $element->appendChild($escaped); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) { danielebarchiesi@4: $element = $doc->createElement(is_numeric($name) ? 'item' : $name); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: self::addToXML($doc, $element, $property); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: catch (EntityMetadataWrapperException $e) { danielebarchiesi@4: // A property causes problems - ignore that. danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public static function setXMLReference(DOMElement $node, $resource, $id) { danielebarchiesi@4: $node->nodeValue = restws_resource_uri($resource, $id); danielebarchiesi@4: $node->setAttribute('resource', $resource); danielebarchiesi@4: $node->setAttribute('id', $id); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * A simple formatter for RDF. Requires the RDF module for the mapping. danielebarchiesi@4: */ danielebarchiesi@4: class RestWSFormatRDF extends RestWSBaseFormat { danielebarchiesi@4: danielebarchiesi@4: protected $namespaces; danielebarchiesi@4: danielebarchiesi@4: public function __construct($name, $info) { danielebarchiesi@4: parent::__construct($name, $info); danielebarchiesi@4: $this->namespaces = rdf_get_namespaces(); danielebarchiesi@4: $this->namespaces['rdf'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'; danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Gets the representation of a resource. danielebarchiesi@4: */ danielebarchiesi@4: public function viewResource($resourceController, $id) { danielebarchiesi@4: $xml = new DOMDocument('1.0', 'utf-8'); danielebarchiesi@4: $rdf_element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:RDF'); danielebarchiesi@4: $xml->appendChild($rdf_element); danielebarchiesi@4: danielebarchiesi@4: $element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:Description'); danielebarchiesi@4: $element->setAttributeNS($this->namespaces['rdf'], 'rdf:about', restws_resource_uri($resourceController->resource(), $id)); danielebarchiesi@4: danielebarchiesi@4: // Add the RDF type of the resource if there is a mapping. danielebarchiesi@4: $entity = $resourceController->read($id); danielebarchiesi@4: if (!empty($entity->rdf_mapping['rdftype'])) { danielebarchiesi@4: foreach ($entity->rdf_mapping['rdftype'] as $rdf_type) { danielebarchiesi@4: $type_element = $xml->createElementNS($this->namespaces['rdf'], 'rdf:type'); danielebarchiesi@4: list($ns, $name) = explode(':', $rdf_type); danielebarchiesi@4: $type_element->setAttributeNS($this->namespaces['rdf'], 'rdf:resource', $this->namespaces[$ns] . $name); danielebarchiesi@4: $element->appendChild($type_element); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: $this->addToXML($xml, $element, $resourceController->wrapper($id)); danielebarchiesi@4: $rdf_element->appendChild($element); danielebarchiesi@4: danielebarchiesi@4: $function = __FUNCTION__; danielebarchiesi@4: drupal_alter('restws_response', $xml, $function, $this->formatName); danielebarchiesi@4: danielebarchiesi@4: return $xml->saveXML(); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function createResource($resourceController, $data) { danielebarchiesi@4: throw new RestWSException('Not implemented', 501); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function updateResource($resourceController, $id, $data) { danielebarchiesi@4: throw new RestWSException('Not implemented', 501); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function queryResource($resourceController, $parameters) { danielebarchiesi@4: throw new RestWSException('Not implemented', 501); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Adds the data of the given wrapper to the given XML element. danielebarchiesi@4: */ danielebarchiesi@4: public function addToXML(DOMDocument $doc, DOMNode $parent, $wrapper) { danielebarchiesi@4: $filtered = restws_property_access_filter($wrapper); danielebarchiesi@4: foreach ($filtered as $name => $property) { danielebarchiesi@4: try { danielebarchiesi@4: if ($property instanceof EntityDrupalWrapper) { danielebarchiesi@4: // For referenced entities only return the URI. danielebarchiesi@4: if ($id = $property->getIdentifier()) { danielebarchiesi@4: $element = $this->addRdfElement($doc, $wrapper, $name); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: $this->addReference($doc, $element, $property->type(), $id); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityValueWrapper) { danielebarchiesi@4: $element = $this->addRdfElement($doc, $wrapper, $name); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: $element->nodeValue = $property->value(); danielebarchiesi@4: } danielebarchiesi@4: elseif ($property instanceof EntityListWrapper || $property instanceof EntityStructureWrapper) { danielebarchiesi@4: $element = $this->addRdfElement($doc, $wrapper, $name); danielebarchiesi@4: $parent->appendChild($element); danielebarchiesi@4: $node = $doc->createElementNS($this->namespaces['rdf'], 'rdf:Description'); danielebarchiesi@4: $element->appendChild($node); danielebarchiesi@4: $this->addToXML($doc, $node, $property); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: catch (EntityMetadataWrapperException $e) { danielebarchiesi@4: // A property causes problems - ignore that. danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: public function addReference(DomDocument $doc, DOMElement $node, $resource, $id) { danielebarchiesi@4: $element = $doc->createElementNS($this->namespaces['rdf'], 'rdf:Description'); danielebarchiesi@4: $element->setAttributeNS($this->namespaces['rdf'], 'rdf:about', restws_resource_uri($resource, $id)); danielebarchiesi@4: $node->appendChild($element); danielebarchiesi@4: } danielebarchiesi@4: danielebarchiesi@4: /** danielebarchiesi@4: * Adds an RDF element for the given property of the wrapper using the RDF danielebarchiesi@4: * mapping. danielebarchiesi@4: */ danielebarchiesi@4: public function addRdfElement(DOMDOcument $doc, EntityMetadataWrapper $wrapper, $name) { danielebarchiesi@4: if ($wrapper instanceof EntityDrupalWrapper) { danielebarchiesi@4: $entity = $wrapper->value(); danielebarchiesi@4: if (!empty($entity->rdf_mapping[$name])) { danielebarchiesi@4: // Just make use of the first predicate for now. danielebarchiesi@4: $predicate = reset($entity->rdf_mapping[$name]['predicates']); danielebarchiesi@4: list($ns, $qname) = explode(':', $predicate); danielebarchiesi@4: $element = $doc->createElementNS($this->namespaces[$ns], $predicate); danielebarchiesi@4: danielebarchiesi@4: if (!empty($entity->rdf_mapping[$name]['datatype'])) { danielebarchiesi@4: $element->setAttributeNS($this->namespaces['rdf'], 'rdf:datatype', $entity->rdf_mapping[$name]['datatype']); danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: } danielebarchiesi@4: if (!isset($element)) { danielebarchiesi@4: // For other elements just use the site URL as namespace. danielebarchiesi@4: $element = $doc->createElementNS(url('', array('absolute' => TRUE)), 'site:' . (is_numeric($name) ? 'item' : $name)); danielebarchiesi@4: } danielebarchiesi@4: return $element; danielebarchiesi@4: } danielebarchiesi@4: }