/** * Helper function to get the identifier from a property wrapper. * * @param \EntityMetadataWrapper $property_wrapper * The property wrapper to get the ID from. * * @return string * An identifier. */ protected function propertyIdentifier(\EntityMetadataWrapper $property_wrapper) { // The property wrapper is a reference to another entity get the entity // ID. $file_array = $property_wrapper->value(); $identifier = $file_array['fid']; $resource = $this->getResource(); // TODO: Make sure we still want to support fullView. if (!$resource || !$identifier || isset($resource['fullView']) && $resource['fullView'] === FALSE) { return $identifier; } // If there is a resource that we are pointing to, we need to use the id // field that that particular resource has in its configuration. Trying to // load by the entity id in that scenario will lead to a 404. // We'll load the plugin to get the idField configuration. $instance_id = sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion']); /* @var ResourceInterface $resource */ $resource = restful()->getResourceManager()->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET)); $plugin_definition = $resource->getPluginDefinition(); if (empty($plugin_definition['dataProvider']['idField'])) { return $identifier; } try { $file_wrapper = entity_metadata_wrapper('file', $file_array['fid']); return $file_wrapper->{$plugin_definition['dataProvider']['idField']}->value(); } catch (\EntityMetadataWrapperException $e) { return $identifier; } }
/** * {@inheritdoc} */ public static function init(RequestInterface $request, $resource_name, array $version, $resource_path = NULL) { /* @var ResourceInterface $resource */ $instance_id = $resource_name . PluginBase::DERIVATIVE_SEPARATOR . $version[0] . '.' . $version[1]; $resource = restful()->getResourceManager()->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET)); $plugin_definition = $resource->getPluginDefinition(); $resource->setPath($resource_path); return new static($request, $resource->getFieldDefinitions(), $resource->getAccount(), $resource->getPluginId(), $resource->getPath(), $plugin_definition['dataProvider'], static::getLanguage(), $resource); }
/** * Get the (reference) field information for a single item. * * @param ResourceFieldInterface $resource_field * The resource field. * * @throws \Drupal\restful\Exception\BadRequestException * * @return array * An array containing the following keys: * - 'name': Drupal's internal field name. Ex: field_article_related * - 'type': Either a field or a property. * - 'entity_type': The entity type this field points to. Not populated if * the field is not a reference (for instance the destination field used * in the where clause). * - 'bundles': The allowed bundles for this field. Not populated if the * field is not a reference (for instance the destination field used in * the where clause). */ protected function getFieldsFromPublicNameItem(ResourceFieldInterface $resource_field) { $property = $resource_field->getProperty(); $resource = $resource_field->getResource(); $item = array('name' => $property, 'type' => ResourceFieldEntity::propertyIsField($property) ? RelationalFilterInterface::TYPE_FIELD : RelationalFilterInterface::TYPE_PROPERTY, 'entity_type' => NULL, 'bundles' => array()); $item['column'] = $item['type'] == RelationalFilterInterface::TYPE_FIELD ? $resource_field->getColumn() : NULL; $instance_id = sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion']); /* @var ResourceEntity $resource */ $resource = restful()->getResourceManager()->getPluginCopy($instance_id, Request::create('', array(), RequestInterface::METHOD_GET)); // Variables for the next iteration. $definitions = $resource->getFieldDefinitions(); $item['entity_type'] = $resource->getEntityType(); $item['bundles'] = $resource->getBundles(); return array($item, $definitions); }
/** * Factory method. * * @return RestfulManager * The newly created manager. */ public static function createFromGlobals() { $request = Request::createFromGlobals(); $response = Response::create(); $resource_manager = new ResourceManager($request); $formatter_manager = new FormatterManager(); $persistable_cache = new PersistableCache(RenderCache::CACHE_BIN); return new static($request, $response, $resource_manager, $formatter_manager, $persistable_cache); }
/** * {@inheritdoc} */ public static function subRequest(array $value) { if (empty($value['request'])) { throw new BadRequestException('Malformed body payload. Missing "request" key for the sub-request.'); } if (empty($value['request']['method'])) { throw new BadRequestException('Malformed body payload. Missing "method" int the "request" key for the sub-request.'); } $request_user_info = $value['request'] + array('path' => NULL, 'query' => array(), 'csrf_token' => NULL); $headers = empty($request_user_info['headers']) ? array() : $request_user_info['headers']; $request_user_info['headers'] = new HttpHeaderBag($headers); $request_user_info['via_router'] = FALSE; $request_user_info['cookies'] = $_COOKIE; $request_user_info['files'] = $_FILES; $request_user_info['server'] = $_SERVER; return Request::create($request_user_info['path'], $request_user_info['query'], $request_user_info['method'], $request_user_info['headers'], $request_user_info['via_router'], $request_user_info['csrf_token'], $request_user_info['cookies'], $request_user_info['files'], $request_user_info['server']); }
/** * Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9. * * @link http://support.microsoft.com/kb/323308 */ protected function ensureIEOverSSLCompatibility(Request $request) { $server_info = $request->getServer(); if (stripos($this->headers->get('Content-Disposition')->getValueString(), 'attachment') !== FALSE && preg_match('/MSIE (.*?);/i', $server_info['HTTP_USER_AGENT'], $match) == 1 && $request->isSecure() === TRUE) { if (intval(preg_replace("/(MSIE )(.*?);/", "\$2", $match[0])) < 9) { $this->headers->remove('Cache-Control'); } } }
/** * {@inheritdoc} */ public function doDelete($path) { if (!$path) { throw new BadRequestException('DELETE requires a path. None given.'); } $this->setPath($path); $this->setRequest(Request::create($this->versionedUrl($path, array('absolute' => FALSE)), array(), RequestInterface::METHOD_DELETE)); return $this->process(); }
/** * Returns the value for the current single field. * * This implementation will also add some metadata to the resource field * object about the entity it is referencing. * * @param \EntityMetadataWrapper $property_wrapper * The property wrapper. Either \EntityDrupalWrapper or \EntityListWrapper. * @param \EntityDrupalWrapper $wrapper * The entity wrapper. * @param object $account * The user account. * * @return mixed * A single value for the field. * * @throws \Drupal\restful\Exception\BadRequestException * @throws \Drupal\restful\Exception\ServerConfigurationException */ protected function singleValue(\EntityMetadataWrapper $property_wrapper, \EntityDrupalWrapper $wrapper, $account) { if ($resource = $this->getResource()) { // TODO: The resource input data in the field definition has changed. // Now it does not need to be keyed by bundle since you don't even need // an entity to use the resource based field. $embedded_identifier = $this->propertyIdentifier($property_wrapper); // Allow embedding entities with ID 0, like the anon user. if (empty($embedded_identifier) && $embedded_identifier !== 0) { return NULL; } if (isset($resource['fullView']) && $resource['fullView'] === FALSE) { return $embedded_identifier; } // We support dot notation for the sparse fieldsets. That means that // clients can specify the fields to show based on the "fields" query // string parameter. $parsed_input = array('fields' => implode(',', $this->nestedDottedChildren('fields')), 'include' => implode(',', $this->nestedDottedChildren('include')), 'filter' => $this->nestedDottedChildren('filter')); $request = Request::create('', array_filter($parsed_input), RequestInterface::METHOD_GET); // Get a plugin (that can be altered with decorators. $embedded_resource = restful()->getResourceManager()->getPluginCopy(sprintf('%s:%d.%d', $resource['name'], $resource['majorVersion'], $resource['minorVersion'])); // Configure the plugin copy with the sub-request and sub-path. $embedded_resource->setPath($embedded_identifier); $embedded_resource->setRequest($request); $embedded_resource->setAccount($account); $metadata = $this->getMetadata($wrapper->getIdentifier()); $metadata = $metadata ?: array(); $metadata[] = $this->buildResourceMetadataItem($property_wrapper); $this->addMetadata($wrapper->getIdentifier(), $metadata); try { // Get the contents to embed in place of the reference ID. /* @var ResourceFieldCollection $embedded_entity */ $embedded_entity = $embedded_resource->getDataProvider()->view($embedded_identifier); } catch (InaccessibleRecordException $e) { // If you don't have access to the embedded entity is like not having // access to the property. return NULL; } catch (UnprocessableEntityException $e) { // If you access a nonexistent embedded entity. return NULL; } // Test if the $embedded_entity meets the filter or not. if (empty($parsed_input['filter'])) { return $embedded_entity; } foreach ($parsed_input['filter'] as $filter) { // Filters only apply if the target is the current field. if (!empty($filter['target']) && $filter['target'] == $this->getPublicName() && !$embedded_entity->evalFilter($filter)) { // This filter is not met. return NULL; } } return $embedded_entity; } if ($this->getFormatter()) { // Get value from field formatter. $value = $this->formatterValue($property_wrapper, $wrapper); } else { // Single value. $value = $this->fieldValue($property_wrapper); } return $value; }
/** * {@inheritdoc} */ public function setMethods($methods) { foreach ($methods as $method) { if (Request::isValidMethod($method)) { throw new ServerConfigurationException(sprintf('The method %s in the field resource mapping is not valid.', $method)); } } $this->methods = $methods; }
/** * Given a field item that contains a cache placeholder render and cache it. * * @param array $field_item * The output to render. * * @param string $includes_path * The includes path encoded in dot notation. * * @return array * The rendered embedded field item. * * @throws \Drupal\restful\Exception\BadRequestException * @throws \Drupal\restful\Exception\InternalServerErrorException */ protected function populateCachePlaceholder(array $field_item, $includes_path) { if (empty($field_item['#cache_placeholder']) || empty($field_item['#resource_id']) || empty($field_item['#resource_plugin'])) { return $field_item; } $embedded_resource = restful()->getResourceManager()->getPluginCopy($field_item['#resource_plugin']); $input = $this->getRequest()->getParsedInput(); $new_input = $input + array('include' => '', 'fields' => ''); // If the field is not supposed to be included, then bail. $old_includes = array_filter(explode(',', $new_input['include'])); if (!in_array($includes_path, $old_includes)) { return $field_item; } $new_input['fields'] = implode(',', $this->unprefixInputOptions(explode(',', $new_input['fields']), $includes_path)); $new_input['include'] = implode(',', $this->unprefixInputOptions($old_includes, $includes_path)); // Create a new request from scratch copying most of the values but the // $query. $embedded_resource->setRequest(Request::create($this->getRequest()->getPath(), array_filter($new_input), $this->getRequest()->getMethod(), $this->getRequest()->getHeaders(), $this->getRequest()->isViaRouter(), $this->getRequest()->getCsrfToken(), $this->getRequest()->getCookies(), $this->getRequest()->getFiles(), $this->getRequest()->getServer(), $this->getRequest()->getParsedBody())); try { $data = $embedded_resource->getDataProvider()->view($field_item['#resource_id']); } catch (InaccessibleRecordException $e) { // Populate it with an empty element. $data = array(); } return array_merge($field_item, $this->extractFieldValues($data, $field_item['#cache_placeholder']['parents'], $field_item['#cache_placeholder']['parent_hashes'])); }