abstract class Formatter in RESTful 7.2
Same name in this branch
- 7.2 src/Annotation/Formatter.php \Drupal\restful\Annotation\Formatter
- 7.2 src/Plugin/formatter/Formatter.php \Drupal\restful\Plugin\formatter\Formatter
Class Formatter.
@package Drupal\restful\Plugin\formatter
Hierarchy
- class \Drupal\restful\Plugin\formatter\Formatter extends \Drupal\Component\Plugin\PluginBase implements FormatterInterface uses ConfigurablePluginTrait
Expanded class hierarchy of Formatter
File
- src/
Plugin/ formatter/ Formatter.php, line 25 - Contains \Drupal\restful\Plugin\formatter\Formatter
Namespace
Drupal\restful\Plugin\formatterView source
abstract class Formatter extends PluginBase implements FormatterInterface {
use ConfigurablePluginTrait;
/**
* The resource handler containing more info about the request.
*
* @var ResourceInterface
*/
protected $resource;
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
}
/**
* {@inheritdoc}
*/
public function format(array $data) {
return $this
->render($this
->prepare($data));
}
/**
* {@inheritdoc}
*/
public function getContentTypeHeader() {
// Default to the most generic content type.
return 'application/hal+json; charset=utf-8';
}
/**
* {@inheritdoc}
*/
public function getResource() {
if (isset($this->resource)) {
return $this->resource;
}
// Get the resource from the instance configuration.
$instance_configuration = $this
->getConfiguration();
if (empty($instance_configuration['resource'])) {
return NULL;
}
$this->resource = $instance_configuration['resource'] instanceof ResourceInterface ? $instance_configuration['resource'] : NULL;
return $this->resource;
}
/**
* {@inheritdoc}
*/
public function setResource(ResourceInterface $resource) {
$this->resource = $resource;
$this
->setConfiguration(array(
'resource' => $resource,
));
}
/**
* {@inheritdoc}
*/
public function parseBody($body) {
throw new ServerConfigurationException(sprintf('Invalid body parser for: %s.', $body));
}
/**
* Helper function to know if a variable is iterable or not.
*
* @param mixed $input
* The variable to test.
*
* @return bool
* TRUE if the variable is iterable.
*/
protected static function isIterable($input) {
return is_array($input) || $input instanceof \Traversable || $input instanceof \stdClass;
}
/**
* Checks if the passed in data to be rendered can be cached.
*
* @param mixed $data
* The data to be prepared and rendered.
*
* @return bool
* TRUE if the data can be cached.
*/
protected function isCacheEnabled($data) {
// We are only caching field collections, but you could cache at different
// layers too.
if (!$data instanceof ResourceFieldCollectionInterface) {
return FALSE;
}
if (!($context = $data
->getContext())) {
return FALSE;
}
return !empty($context['cache_fragments']);
}
/**
* Gets the cached computed value for the fields to be rendered.
*
* @param mixed $data
* The data to be rendered.
*
* @return mixed
* The cached data.
*/
protected function getCachedData($data) {
if (!($render_cache = $this
->createCacheController($data))) {
return NULL;
}
return $render_cache
->get();
}
/**
* Gets the cached computed value for the fields to be rendered.
*
* @param mixed $data
* The data to be rendered.
*
* @return string
* The cache hash.
*/
protected function getCacheHash($data) {
if (!($render_cache = $this
->createCacheController($data))) {
return NULL;
}
return $render_cache
->getCid();
}
/**
* Gets the cached computed value for the fields to be rendered.
*
* @param mixed $data
* The data to be rendered.
* @param mixed $output
* The rendered data to output.
* @param string[] $parent_hashes
* An array that holds the name of the parent cache hashes that lead to the
* current data structure.
*/
protected function setCachedData($data, $output, array $parent_hashes = array()) {
if (!($render_cache = $this
->createCacheController($data))) {
return;
}
$render_cache
->set($output);
// After setting the cache for the current object, mark all parent hashes
// with the current cache fragments. That will have the effect of allowing
// to clear the parent caches based on the children fragments.
$fragments = $this
->cacheFragments($data);
foreach ($parent_hashes as $parent_hash) {
foreach ($fragments as $tag_type => $tag_value) {
// Check if the fragment already exists.
$query = new \EntityFieldQuery();
$duplicate = (bool) $query
->entityCondition('entity_type', 'cache_fragment')
->propertyCondition('value', $tag_value)
->propertyCondition('type', $tag_type)
->propertyCondition('hash', $parent_hash)
->count()
->execute();
if ($duplicate) {
continue;
}
$cache_fragment = new CacheFragment(array(
'value' => $tag_value,
'type' => $tag_type,
'hash' => $parent_hash,
), 'cache_fragment');
try {
$cache_fragment
->save();
} catch (\Exception $e) {
watchdog_exception('restful', $e);
}
}
}
}
/**
* Gets a cache controller based on the data to be rendered.
*
* @param mixed $data
* The data to be rendered.
*
* @return \Drupal\restful\RenderCache\RenderCacheInterface;
* The cache controller.
*/
protected function createCacheController($data) {
if (!($cache_fragments = $this
->cacheFragments($data))) {
return NULL;
}
// Add the formatter fragment because every formatter may prepare the data
// differently.
/* @var \Doctrine\Common\Collections\ArrayCollection $cache_fragments */
$cache_fragments
->set('formatter', $this
->getPluginId());
/* @var \Drupal\restful\Plugin\resource\Decorators\CacheDecoratedResource $cached_resource */
if (!($cached_resource = $this
->getResource())) {
return NULL;
}
if (!$cached_resource instanceof CacheDecoratedResourceInterface) {
return NULL;
}
return RenderCache::create($cache_fragments, $cached_resource
->getCacheController());
}
/**
* Gets a cache fragments based on the data to be rendered.
*
* @param mixed $data
* The data to be rendered.
*
* @return \Doctrine\Common\Collections\ArrayCollection;
* The cache controller.
*/
protected static function cacheFragments($data) {
$context = $data
->getContext();
if (!($cache_fragments = $context['cache_fragments'])) {
return NULL;
}
return $cache_fragments;
}
/**
* Returns only the allowed fields by filtering out the other ones.
*
* @param mixed $output
* The data structure to filter.
* @param bool|string[] $allowed_fields
* FALSE to allow all fields. An array of allowed values otherwise.
*
* @return mixed
* The filtered output.
*/
protected function limitFields($output, $allowed_fields = NULL) {
if (!isset($allowed_fields)) {
$request = ($resource = $this
->getResource()) ? $resource
->getRequest() : restful()
->getRequest();
$input = $request
->getParsedInput();
// Set the field limits to false if there are no limits.
$allowed_fields = empty($input['fields']) ? FALSE : explode(',', $input['fields']);
}
if (!is_array($output)) {
// $output is a simple value.
return $output;
}
$result = array();
if (ResourceFieldBase::isArrayNumeric($output)) {
foreach ($output as $item) {
$result[] = $this
->limitFields($item, $allowed_fields);
}
return $result;
}
foreach ($output as $field_name => $field_contents) {
if ($allowed_fields !== FALSE && !in_array($field_name, $allowed_fields)) {
continue;
}
$result[$field_name] = $this
->limitFields($field_contents, $this
->unprefixInputOptions($allowed_fields, $field_name));
}
return $result;
}
/**
* Given a prefix, return the allowed fields that apply removing the prefix.
*
* @param bool|string[] $allowed_fields
* The list of allowed fields in dot notation.
* @param string $prefix
* The prefix used to select the fields and to remove from the front.
*
* @return bool|string[]
* The new allowed fields for the nested sub-request.
*/
protected static function unprefixInputOptions($allowed_fields, $prefix) {
if ($allowed_fields === FALSE) {
return FALSE;
}
$closure_unprefix = function ($field_limit) use ($prefix) {
if ($field_limit == $prefix) {
return NULL;
}
$pos = strpos($field_limit, $prefix . '.');
// Remove the prefix from the $field_limit.
return $pos === 0 ? substr($field_limit, strlen($prefix . '.')) : NULL;
};
return array_filter(array_map($closure_unprefix, $allowed_fields));
}
/**
* Helper function that calculates the number of items per page.
*
* @param ResourceInterface $resource
* The associated resource.
*
* @return int
* The items per page.
*/
protected function calculateItemsPerPage(ResourceInterface $resource) {
$data_provider = $resource
->getDataProvider();
$max_range = $data_provider
->getRange();
$original_input = $resource
->getRequest()
->getPagerInput();
$items_per_page = empty($original_input['size']) ? $max_range : $original_input['size'];
return $items_per_page > $max_range ? $max_range : $items_per_page;
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ConfigurablePluginTrait:: |
protected | property | Plugin instance configuration. | |
ConfigurablePluginTrait:: |
public | function | ||
ConfigurablePluginTrait:: |
public | function | 1 | |
ConfigurablePluginTrait:: |
public | function | ||
ConfigurablePluginTrait:: |
public | function | ||
Formatter:: |
protected | property | The resource handler containing more info about the request. | |
Formatter:: |
protected static | function | Gets a cache fragments based on the data to be rendered. | |
Formatter:: |
protected | function | Helper function that calculates the number of items per page. | |
Formatter:: |
protected | function | Gets a cache controller based on the data to be rendered. | |
Formatter:: |
public | function |
Formats the un-structured data into the output format. Overrides FormatterInterface:: |
|
Formatter:: |
protected | function | Gets the cached computed value for the fields to be rendered. | |
Formatter:: |
protected | function | Gets the cached computed value for the fields to be rendered. | |
Formatter:: |
public | function |
Returns the content type for the selected output format. Overrides FormatterInterface:: |
3 |
Formatter:: |
public | function |
Gets the underlying resource. Overrides FormatterInterface:: |
|
Formatter:: |
protected | function | Checks if the passed in data to be rendered can be cached. | |
Formatter:: |
protected static | function | Helper function to know if a variable is iterable or not. | |
Formatter:: |
protected | function | Returns only the allowed fields by filtering out the other ones. | |
Formatter:: |
public | function |
Parses the body string into the common format. Overrides FormatterInterface:: |
2 |
Formatter:: |
protected | function | Gets the cached computed value for the fields to be rendered. | |
Formatter:: |
public | function |
Sets the underlying resource. Overrides FormatterInterface:: |
|
Formatter:: |
protected static | function | Given a prefix, return the allowed fields that apply removing the prefix. | |
Formatter:: |
public | function | ||
FormatterInterface:: |
public | function | Massages the raw data to create a structured array to pass to the renderer. | 3 |
FormatterInterface:: |
public | function | Renders an array in the selected format. | 3 |