/**
  * {@inheritdoc}
  */
 public function getContextValue()
 {
     if (!isset($this->contextData)) {
         $definition = $this->getContextDefinition();
         if ($definition->isRequired()) {
             $type = $definition->getDataType();
             throw new ContextException(String::format("The @type context is required and not present.", array('@type' => $type)));
         }
         return NULL;
     }
     return $this->contextData->getValue();
 }
Example #2
0
 /**
  * {@inheritdoc}
  */
 public function getContextValue()
 {
     if (!isset($this->contextData)) {
         $definition = $this->getContextDefinition();
         if ($definition->isRequired()) {
             $type = $definition->getDataType();
             throw new ContextException(String::format("The @type context is required and not present.", array('@type' => $type)));
         }
         return NULL;
     }
     // Special case entities.
     // @todo: Remove once entities do not implemented TypedDataInterface.
     if ($this->contextData instanceof ContentEntityInterface) {
         return $this->contextData;
     }
     return $this->contextData->getValue();
 }
Example #3
0
 /**
  * {@inheritdoc}
  */
 public function getPropertyPath()
 {
     if (isset($this->parent)) {
         // The property path of this data object is the parent's path appended
         // by this object's name.
         $prefix = $this->parent->getPropertyPath();
         return (strlen($prefix) ? $prefix . '.' : '') . $this->name;
     } elseif (isset($this->name)) {
         return $this->name;
     }
     return '';
 }
Example #4
0
 /**
  * Constructs a FormElementBase.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   The schema element this form element is for.
  */
 public function __construct(TypedDataInterface $element)
 {
     $this->element = $element;
     $this->definition = $element->getDataDefinition();
 }
 /**
  * Gets translatable configuration data for a typed configuration element.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   Typed configuration element.
  *
  * @return array|\Drupal\Core\StringTranslation\TranslatableMarkup
  *   A nested array matching the exact structure under $element with only the
  *   elements that are translatable wrapped into a TranslatableMarkup. If the
  *   provided $element is not traversable, the return value is a single
  *   TranslatableMarkup.
  */
 protected function getTranslatableData(TypedDataInterface $element)
 {
     $translatable = array();
     if ($element instanceof TraversableTypedDataInterface) {
         foreach ($element as $key => $property) {
             $value = $this->getTranslatableData($property);
             if (!empty($value)) {
                 $translatable[$key] = $value;
             }
         }
     } else {
         // Something is only translatable by Locale if there is a string in the
         // first place.
         $value = $element->getValue();
         $definition = $element->getDataDefinition();
         if (!empty($definition['translatable']) && $value !== '' && $value !== NULL) {
             $options = array();
             if (isset($definition['translation context'])) {
                 $options['context'] = $definition['translation context'];
             }
             return new TranslatableMarkup($value, array(), $options);
         }
     }
     return $translatable;
 }
 /**
  * Translates element's value if it fits our translation criteria.
  *
  * For an element to be translatable by locale module it needs to be of base
  * type 'string' and have 'translatable = TRUE' in the element's definition.
  * Translatable elements may use these additional keys in their data
  * definition:
  * - 'translatable', FALSE to opt out of translation.
  * - 'translation context', to define the string context.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   Configuration element.
  * @param array $options
  *   Array with translation options that must contain the following keys:
  *   - 'source', Source language code.
  *   - 'target', Target language code.
  *
  * @return bool
  *   Whether the element fits the translation criteria.
  */
 protected function translateElement(TypedDataInterface $element, array $options)
 {
     if ($this->canTranslate($options['source'], $options['target'])) {
         $definition = $element->getDataDefinition();
         $value = $element->getValue();
         if ($value && !empty($definition['translatable'])) {
             $context = isset($definition['translation context']) ? $definition['translation context'] : '';
             if ($translation = $this->localeConfig->translateString($this->name, $options['target'], $value, $context)) {
                 $element->setValue($translation);
                 return TRUE;
             }
         }
     }
     // The element does not have a translation.
     return FALSE;
 }
Example #7
0
 /**
  * Gets translatable configuration data for a typed configuration element.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   Typed configuration element.
  *
  * @return array|\Drupal\Core\StringTranslation\TranslationWrapper
  *   A nested array matching the exact structure under $element with only the
  *   elements that are translatable wrapped into a TranslationWrapper. If the
  *   provided $element is not traversable, the return value is a single
  *   TranslationWrapper.
  */
 protected function getTranslatableData(TypedDataInterface $element)
 {
     $translatable = array();
     if ($element instanceof TraversableTypedDataInterface) {
         foreach ($element as $key => $property) {
             $value = $this->getTranslatableData($property);
             if (!empty($value)) {
                 $translatable[$key] = $value;
             }
         }
     } else {
         $definition = $element->getDataDefinition();
         if (!empty($definition['translatable'])) {
             $options = array();
             if (isset($definition['translation context'])) {
                 $options['context'] = $definition['translation context'];
             }
             return new TranslationWrapper($element->getValue(), array(), $options);
         }
     }
     return $translatable;
 }
 /**
  * Extracts the value of the property from the given container.
  *
  * @param mixed $container The container to extract the property value from.
  *
  * @return mixed The value of the property.
  */
 public function getPropertyValue($container)
 {
     return $this->typedData->getValue();
 }
 /**
  * Recursive helper for getting all contained strings,
  * i.e. properties of type string.
  */
 public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &$strings)
 {
     if ($wrapper instanceof StringInterface) {
         $strings[] = $wrapper->getValue();
     }
     // Recurse until a certain depth is reached if possible.
     if ($depth < 7) {
         if ($wrapper instanceof \Drupal\Core\TypedData\ListInterface) {
             foreach ($wrapper as $item) {
                 $this->getContainedStrings($item, $depth + 1, $strings);
             }
         } elseif ($wrapper instanceof \Drupal\Core\TypedData\ComplexDataInterface) {
             foreach ($wrapper as $property) {
                 $this->getContainedStrings($property, $depth + 1, $strings);
             }
         }
     }
 }
Example #10
0
 /**
  * {@inheritdoc}
  */
 public function getCanonicalRepresentation(TypedDataInterface $data)
 {
     $data_definition = $data->getDataDefinition();
     // In case a list is passed, respect the 'wrapped' key of its data type.
     if ($data_definition instanceof ListDataDefinitionInterface) {
         $data_definition = $data_definition->getItemDefinition();
     }
     // Get the plugin definition of the used data type.
     $type_definition = $this->getDefinition($data_definition->getDataType());
     if (!empty($type_definition['unwrap_for_canonical_representation'])) {
         return $data->getValue();
     }
     return $data;
 }
 /**
  * Tests the normalize() method.
  */
 public function testNormalize()
 {
     $this->typedData->expects($this->once())->method('getValue')->will($this->returnValue('test'));
     $this->assertEquals('test', $this->normalizer->normalize($this->typedData));
 }
 /**
  * Returns TRUE if at least one translatable element is found.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   Configuration schema element.
  *
  * @return bool
  *   A boolean indicating if there is at least one translatable element.
  */
 protected function findTranslatable(TypedDataInterface $element)
 {
     // In case this is a sequence or a mapping check whether any child element
     // is translatable.
     if ($element instanceof TraversableTypedDataInterface) {
         foreach ($element as $child_element) {
             if ($this->findTranslatable($child_element)) {
                 return TRUE;
             }
         }
         // If none of the child elements are translatable, return FALSE.
         return FALSE;
     } else {
         $definition = $element->getDataDefinition();
         return isset($definition['translatable']) && $definition['translatable'];
     }
 }
Example #13
0
 /**
  * Adds the bubbleable metadata of the given data.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $data
  *   The data of which to add the metadata.
  * @param \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata
  *   The bubbleable metadata to which to add the data.
  */
 protected function addBubbleableMetadata(TypedDataInterface $data, BubbleableMetadata $bubbleable_metadata)
 {
     if ($data instanceof PrimitiveInterface) {
         // Primitives do not have any metadata attached.
         return;
     }
     $value = $data->getValue();
     if ($value instanceof CacheableDependencyInterface || $value instanceof AttachmentsInterface) {
         $bubbleable_metadata->addCacheableDependency($value);
     }
 }
Example #14
0
 /**
  * Implements MetadataInterface::findConstraints().
  */
 public function findConstraints($group)
 {
     return $this->typedData->getConstraints();
 }
 /**
  * Get a typed data instance for a property of a given typed data object.
  *
  * This method will use prototyping for fast and efficient instantiation of
  * many property objects with the same property path; e.g.,
  * when multiple comments are used comment_body.0.value needs to be
  * instantiated very often.
  * Prototyping is done by the root object's data type and the given
  * property path, i.e. all property instances having the same property path
  * and inheriting from the same data type are prototyped.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $object
  *   The parent typed data object, implementing the TypedDataInterface and
  *   either the ListInterface or the ComplexDataInterface.
  * @param string $property_name
  *   The name of the property to instantiate, or the delta of an list item.
  * @param mixed $value
  *   (optional) The data value. If set, it has to match one of the supported
  *   data type formats as documented by the data type classes.
  *
  * @throws \InvalidArgumentException
  *   If the given property is not known, or the passed object does not
  *   implement the ListInterface or the ComplexDataInterface.
  *
  * @return \Drupal\Core\TypedData\TypedDataInterface
  *   The new property instance.
  *
  * @see \Drupal\Core\TypedData\TypedDataManager::create()
  */
 public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL)
 {
     // For performance, try to reuse existing prototypes instead of
     // constructing new objects when possible. A prototype is reused when
     // creating a data object:
     // - for a similar root object (same data type and settings),
     // - at the same property path under that root object.
     $root_definition = $object->getRoot()->getDataDefinition();
     // If the root object is a list, we want to look at the data type and the
     // settings of its item definition.
     if ($root_definition instanceof ListDataDefinition) {
         $root_definition = $root_definition->getItemDefinition();
     }
     // Root data type and settings.
     $parts[] = $root_definition->getDataType();
     if ($settings = $root_definition->getSettings()) {
         // Hash the settings into a string. crc32 is the fastest way to hash
         // something for non-cryptographic purposes.
         $parts[] = crc32(serialize($settings));
     }
     // Property path for the requested data object. When creating a list item,
     // use 0 in the key as all items look the same.
     $parts[] = $object->getPropertyPath() . '.' . (is_numeric($property_name) ? 0 : $property_name);
     $key = implode(':', $parts);
     // Create the prototype if needed.
     if (!isset($this->prototypes[$key])) {
         // Fetch the data definition for the child object from the parent.
         if ($object instanceof ComplexDataInterface) {
             $definition = $object->getDataDefinition()->getPropertyDefinition($property_name);
         } elseif ($object instanceof ListInterface) {
             $definition = $object->getItemDefinition();
         } else {
             throw new \InvalidArgumentException("The passed object has to either implement the ComplexDataInterface or the ListInterface.");
         }
         if (!$definition) {
             throw new \InvalidArgumentException('Property ' . String::checkPlain($property_name) . ' is unknown.');
         }
         // Create the prototype without any value, but with initial parenting
         // so that constructors can set up the objects correclty.
         $this->prototypes[$key] = $this->create($definition, NULL, $property_name, $object);
     }
     // Clone the prototype, update its parenting information, and assign the
     // value.
     $property = clone $this->prototypes[$key];
     $property->setContext($property_name, $object);
     if (isset($value)) {
         $property->setValue($value, FALSE);
     }
     return $property;
 }
 /**
  * Creates a form element builder.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $schema
  *   Schema definition of configuration.
  *
  * @return \Drupal\config_translation\FormElement\ElementInterface|null
  *   The element builder object if possible.
  */
 public static function createFormElement(TypedDataInterface $schema)
 {
     $definition = $schema->getDataDefinition();
     // Form element classes can be specified even for non-translatable elements
     // such as the ListElement form element which is used for Mapping and
     // Sequence schema elements.
     if (isset($definition['form_element_class'])) {
         if (!$definition->getLabel()) {
             $definition->setLabel(t('n/a'));
         }
         $class = $definition['form_element_class'];
         return $class::create($schema);
     }
 }
Example #17
0
 /**
  * Extracts field values from a typed data object.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $data
  *   The typed data object.
  *
  * @return array
  *   An array of values.
  */
 public static function extractFieldValues(TypedDataInterface $data)
 {
     if ($data->getDataDefinition()->isList()) {
         $values = array();
         foreach ($data as $piece) {
             $values[] = self::extractFieldValues($piece);
         }
         return $values ? call_user_func_array('array_merge', $values) : array();
     }
     $value = $data->getValue();
     $definition = $data->getDataDefinition();
     if ($definition instanceof ComplexDataDefinitionInterface) {
         $property = $definition->getMainPropertyName();
         if (isset($value[$property])) {
             return array($value[$property]);
         }
     } elseif (is_array($value)) {
         return array_values($value);
     }
     return array($value);
 }
Example #18
0
 /**
  * {@inheritdoc}
  */
 public function getPropertyName()
 {
     return $this->data->getName();
 }
Example #19
0
 /**
  * Get a typed data instance for a property of a given typed data object.
  *
  * This method will use prototyping for fast and efficient instantiation of
  * many property objects with the same property path; e.g.,
  * when multiple comments are used comment_body.0.value needs to be
  * instantiated very often.
  * Prototyping is done by the root object's data type and the given
  * property path, i.e. all property instances having the same property path
  * and inheriting from the same data type are prototyped.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $object
  *   The parent typed data object, implementing the TypedDataInterface and
  *   either the ListInterface or the ComplexDataInterface.
  * @param string $property_name
  *   The name of the property to instantiate, or the delta of an list item.
  * @param mixed $value
  *   (optional) The data value. If set, it has to match one of the supported
  *   data type formats as documented by the data type classes.
  *
  * @throws \InvalidArgumentException
  *   If the given property is not known, or the passed object does not
  *   implement the ListInterface or the ComplexDataInterface.
  *
  * @return \Drupal\Core\TypedData\TypedDataInterface
  *   The new property instance.
  *
  * @see \Drupal\Core\TypedData\TypedDataManager::create()
  */
 public function getPropertyInstance(TypedDataInterface $object, $property_name, $value = NULL)
 {
     $definition = $object->getRoot()->getDataDefinition();
     // If the definition is a list, we need to look at the data type and the
     // settings of its item definition.
     if ($definition instanceof ListDataDefinition) {
         $definition = $definition->getItemDefinition();
     }
     $key = $definition->getDataType();
     if ($settings = $definition->getSettings()) {
         $key .= ':' . Crypt::hashBase64(serialize($settings));
     }
     $key .= ':' . $object->getPropertyPath() . '.';
     // If we are creating list items, we always use 0 in the key as all list
     // items look the same.
     $key .= is_numeric($property_name) ? 0 : $property_name;
     // Make sure we have a prototype. Then, clone the prototype and set object
     // specific values, i.e. the value and the context.
     if (!isset($this->prototypes[$key]) || !$key) {
         // Create the initial prototype. For that we need to fetch the definition
         // of the to be created property instance from the parent.
         if ($object instanceof ComplexDataInterface) {
             $definition = $object->getDataDefinition()->getPropertyDefinition($property_name);
         } elseif ($object instanceof ListInterface) {
             $definition = $object->getItemDefinition();
         } else {
             throw new \InvalidArgumentException("The passed object has to either implement the ComplexDataInterface or the ListInterface.");
         }
         // Make sure we have got a valid definition.
         if (!$definition) {
             throw new \InvalidArgumentException('Property ' . String::checkPlain($property_name) . ' is unknown.');
         }
         // Now create the prototype using the definition, but do not pass the
         // given value as it will serve as prototype for any further instance.
         $this->prototypes[$key] = $this->create($definition, NULL, $property_name, $object);
     }
     // Clone from the prototype, then update the parent relationship and set the
     // data value if necessary.
     $property = clone $this->prototypes[$key];
     $property->setContext($property_name, $object);
     if (isset($value)) {
         $property->setValue($value, FALSE);
     }
     return $property;
 }
Example #20
0
 /**
  * Extracts value and original type from a single piece of data.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $data
  *   The piece of data from which to extract information.
  * @param \Drupal\search_api\Item\FieldInterface $field
  *   The field into which to put the extracted data.
  */
 public static function extractField(TypedDataInterface $data, FieldInterface $field)
 {
     if ($data->getDataDefinition()->isList()) {
         foreach ($data as $piece) {
             self::extractField($piece, $field);
         }
         return;
     }
     $value = $data->getValue();
     $definition = $data->getDataDefinition();
     if ($definition instanceof ComplexDataDefinitionInterface) {
         $property = $definition->getMainPropertyName();
         if (isset($value[$property])) {
             $value = $value[$property];
         }
     } elseif (is_array($value)) {
         $value = reset($value);
     }
     // If the data type of the field is a custom one, then the value can be
     // altered by the data type plugin.
     $data_type_manager = \Drupal::service('plugin.manager.search_api.data_type');
     if ($data_type_manager->hasDefinition($field->getType())) {
         $value = $data_type_manager->createInstance($field->getType())->getValue($value);
     }
     $field->addValue($value);
     $field->setOriginalType($definition->getDataType());
 }
Example #21
0
 /**
  * {@inheritdoc}
  */
 public function getConstraints()
 {
     return $this->typedData->getConstraints();
 }
 /**
  * Formats a value as a string, for readable output.
  *
  * @param \Drupal\Core\TypedData\TypedDataInterface $element
  *   The value element.
  *
  * @return string
  *   The value in string form.
  */
 protected function formatValue(TypedDataInterface $element)
 {
     $value = $element->getValue();
     if (is_scalar($value)) {
         return SafeMarkup::checkPlain($value);
     }
     if (empty($value)) {
         return '<' . $this->t('empty') . '>';
     }
     return '<' . gettype($value) . '>';
 }