/**
  * 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']));
 }