1<?php 2 3namespace Drupal\serialization\Normalizer; 4 5use Drupal\Component\Plugin\PluginInspectionInterface; 6use Drupal\Core\Field\FieldItemInterface; 7 8/** 9 * A trait providing methods for serialized columns. 10 */ 11trait SerializedColumnNormalizerTrait { 12 13 /** 14 * Checks if there is a serialized string for a column. 15 * 16 * @param mixed $data 17 * The field item data to denormalize. 18 * @param string $class 19 * The expected class to instantiate. 20 * @param \Drupal\Core\Field\FieldItemInterface $field_item 21 * The field item. 22 */ 23 protected function checkForSerializedStrings($data, $class, FieldItemInterface $field_item) { 24 // Require specialized denormalizers for fields with 'serialize' columns. 25 // Note: this cannot be checked in ::supportsDenormalization() because at 26 // that time we only have the field item class. ::hasSerializeColumn() 27 // must be able to call $field_item->schema(), which requires a field 28 // storage definition. To determine that, the entity type and bundle 29 // must be known, which is contextual information that the Symfony 30 // serializer does not pass to ::supportsDenormalization(). 31 if (!is_array($data)) { 32 $data = [$field_item->getDataDefinition()->getMainPropertyName() => $data]; 33 } 34 if ($this->dataHasStringForSerializeColumn($field_item, $data)) { 35 $field_name = $field_item->getParent() ? $field_item->getParent()->getName() : $field_item->getName(); 36 throw new \LogicException(sprintf('The generic FieldItemNormalizer cannot denormalize string values for "%s" properties of the "%s" field (field item class: %s).', implode('", "', $this->getSerializedPropertyNames($field_item)), $field_name, $class)); 37 } 38 } 39 40 /** 41 * Checks if the data contains string value for serialize column. 42 * 43 * @param \Drupal\Core\Field\FieldItemInterface $field_item 44 * The field item. 45 * @param array $data 46 * The data being denormalized. 47 * 48 * @return bool 49 * TRUE if there is a string value for serialize column, otherwise FALSE. 50 */ 51 protected function dataHasStringForSerializeColumn(FieldItemInterface $field_item, array $data) { 52 foreach ($this->getSerializedPropertyNames($field_item) as $property_name) { 53 if (isset($data[$property_name]) && is_string($data[$property_name])) { 54 return TRUE; 55 } 56 } 57 return FALSE; 58 } 59 60 /** 61 * Gets the names of all serialized properties. 62 * 63 * @param \Drupal\Core\Field\FieldItemInterface $field_item 64 * The field item. 65 * 66 * @return string[] 67 * The property names for serialized properties. 68 */ 69 protected function getSerializedPropertyNames(FieldItemInterface $field_item) { 70 $field_storage_definition = $field_item->getFieldDefinition()->getFieldStorageDefinition(); 71 72 if ($custom_property_names = $this->getCustomSerializedPropertyNames($field_item)) { 73 return $custom_property_names; 74 } 75 76 $field_storage_schema = $field_item->schema($field_storage_definition); 77 // If there are no columns then there are no serialized properties. 78 if (!isset($field_storage_schema['columns'])) { 79 return []; 80 } 81 $serialized_columns = array_filter($field_storage_schema['columns'], function ($column_schema) { 82 return isset($column_schema['serialize']) && $column_schema['serialize'] === TRUE; 83 }); 84 return array_keys($serialized_columns); 85 } 86 87 /** 88 * Gets the names of all properties the plugin treats as serialized data. 89 * 90 * This allows the field storage definition or entity type to provide a 91 * setting for serialized properties. This can be used for fields that 92 * handle serialized data themselves and do not rely on the serialized schema 93 * flag. 94 * 95 * @param \Drupal\Core\Field\FieldItemInterface $field_item 96 * The field item. 97 * 98 * @return string[] 99 * The property names for serialized properties. 100 */ 101 protected function getCustomSerializedPropertyNames(FieldItemInterface $field_item) { 102 if ($field_item instanceof PluginInspectionInterface) { 103 $definition = $field_item->getPluginDefinition(); 104 $serialized_fields = $field_item->getEntity()->getEntityType()->get('serialized_field_property_names'); 105 $field_name = $field_item->getFieldDefinition()->getName(); 106 if (is_array($serialized_fields) && isset($serialized_fields[$field_name]) && is_array($serialized_fields[$field_name])) { 107 return $serialized_fields[$field_name]; 108 } 109 if (isset($definition['serialized_property_names']) && is_array($definition['serialized_property_names'])) { 110 return $definition['serialized_property_names']; 111 } 112 } 113 return []; 114 } 115 116} 117