├── README.md ├── distill.info.yml ├── distill.module └── src ├── Distill.php └── DistillProcessor.php /README.md: -------------------------------------------------------------------------------- 1 | # Distill 2 | Distill is a Drupal module that enables other modules to extract and format 3 | data from Drupal entities. It provides a simple class structure for defining 4 | formatting schemas. 5 | 6 | ## How does Distill Work? 7 | Distill contains 2 classes. 1) A class that defines the structure of a 8 | processor and 2) a distillation class that takes an entity, a processor class, 9 | and a list of fields that should be returned, executes the processor’s 10 | formatter methods, and returns an array of data. If the processor passed into 11 | the distillation class doesn't have a processor for a specific field type, 12 | then it will default to invoking the hook defined for that field type. 13 | 14 | ### Distill class 15 | `Distill` is a class that takes an entity type, entity, processor, and 16 | language. When asked, it will go through fields, process them with the 17 | methods as defined in the passed-in processor (defaulting to the field type 18 | hooks if no processor function is available), and add them to an array of 19 | field values. It contains a few methods that allow you to ask for fields, and 20 | grab field values. 21 | 22 | - `setField('field_name', 'property_name', array('settings'))`: Asks the 23 | distiller to process a given field, and add it to the array of processed fields 24 | with the key as specified in the `property_name` parameter. This function also 25 | takes a settings array, which gets passed into the processor class and allows 26 | one to pass context to the processor function. 27 | - `setAllFields()`: Tells the distiller that all fields should be formatted 28 | and returned. 29 | - `getFieldValues()`: Returns the array of field data that has been extracted 30 | from the given entity and processed by the distiller. 31 | 32 | ### DistillProcessor class 33 | The `DistillProcessor` class contains methods that provide a sensible default 34 | for extracting and formatting data from fields. The methods are called based 35 | on the field type, or name. 36 | 37 | You can create your own processor class that extends `DistillProcessor`, and 38 | easily override processor methods by simply creating methods in the following 39 | pattern: 40 | 41 | #### Field Type Processor Methods 42 | Field type processor methods are called based on the **type** of field that is 43 | currently being processed. The pattern for creating these method names is 44 | `process*Typename*Type()`, where `*Typename*` is equal to the type of field 45 | this method should process (such as `Text` or `Entityreference`). If your 46 | processor class does not have a method for processing a particular type of 47 | field, then it will invoke `hook_distill_process_*field_type*()`. These 48 | hooks should be implemented by the module defining the field type, or within 49 | the `distill.module` file. 50 | 51 | 52 | #### Field Name Processor Methods 53 | Field name processor methods are called based on the **name** of the field 54 | that's currently being processed. The patter for creating these method names 55 | is `process*Fieldname*Field()`, where `*Fieldname*` is equal to the name of 56 | the field this method should process (such as `Fieldimage` or `Body`). 57 | 58 | All processor methods take 3 parameters: 59 | 60 | - `$wrapper`: EntityStructureWrapper|EntityValueWrapper of field from which 61 | values are being extracted. 62 | - `$index`: Integer representing the delta of the field being processed. 63 | - `$settings`: Variable for passing in settings and context that will affect 64 | how the field value should be processed. 65 | 66 | #### Example 67 | Here's a quick example implementation of this module within a route controller: 68 | 69 | ```php 70 | namespace Drupal\my_module\Controller; 71 | use Drupal\Core\Controller\ControllerBase; 72 | use Symfony\Component\HttpFoundation\JsonResponse; 73 | 74 | // Load Distill classes. 75 | use Drupal\distill\Distill; 76 | use Drupal\distill\DistillProcessor; 77 | 78 | /** 79 | * Controller routines for my_module routes. 80 | */ 81 | class DistillExampleController extends ControllerBase { 82 | /** 83 | * Returns a blob of yummy json. 84 | */ 85 | public function exampleDataExtrationEndpoint() { 86 | $entity = \Drupal::entityManager()->getStorage('node')->load(1); 87 | 88 | // Create instance of processor. 89 | $processor = new DistillProcessor(); 90 | 91 | // Create instance of Distill. 92 | $distiller = new Distill($entity, $processor); 93 | 94 | // Specify which fields should be returned. 95 | $distiller->setField('nid', '_id'); 96 | $distiller->setField('title'); 97 | $distiller->setField('body', 'post'); 98 | 99 | // We pass in an image style. 100 | $distiller->setField('field_image', 'image', array('image_style' => 'thumbnail')); 101 | 102 | // This is an entity reference field. We pass a settings array 103 | // that has an 'include_fields' key. This key contains an array of fields 104 | // from the referenced entity that should be returned. 105 | $distiller->setField('field_author', 'user', array( 106 | 'include_fields' => array( 107 | 'name', 108 | 'mail' 109 | ) 110 | )); 111 | 112 | // Output the returned array as JSON. 113 | return new JsonResponse($distiller->getFieldValues()); 114 | } 115 | } 116 | 117 | ``` 118 | 119 | And here's an example of an entity that's been processed and formatted as JSON: 120 | 121 | ```javascript 122 | { 123 | title: "Hello World!", 124 | post: "

This is a post body.

", 125 | image: "http://d7.local/sites/default/files/styles/thumbnail/field/image/whoa.jpg", 126 | user: { 127 | name: "admin", 128 | mail: "patrickcoffey48@gmail.com" 129 | } 130 | } 131 | ``` 132 | 133 | ## What's Next? 134 | Distill is still under development. Here are some things that are likely to surface soon: 135 | 136 | * distill_extra module that contains lots of field-type default formatters. 137 | * Drupal 8 version of Distill. 138 | * RestFull/Distill implementation. 139 | * Better documentation. 140 | * Panels pane that allows developers to easily create and theme panes of content. 141 | -------------------------------------------------------------------------------- /distill.info.yml: -------------------------------------------------------------------------------- 1 | name: Distill 2 | description: 'Provides an API that allows modules to easily extract and format data from Entity objects.' 3 | package: Entity 4 | core: 8.x 5 | php: '5.3' 6 | dependencies: 7 | type: module 8 | -------------------------------------------------------------------------------- /distill.module: -------------------------------------------------------------------------------- 1 | getValue(); 27 | return $value[0]['value']; 28 | } 29 | 30 | /** 31 | * Processor for fields of type 'float'. 32 | * 33 | * @param Drupal\Core\Field\FieldItemList $field 34 | * Object representing a configurable field on an entity. 35 | * @param int $index 36 | * Delta of field being processed. 37 | * @param array $settings 38 | * Processor configuration and context. 39 | * 40 | * @return string 41 | * Processed value of field. 42 | */ 43 | function distill_distill_process_float(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 44 | $value = $field->getValue(); 45 | return $value[0]['value']; 46 | } 47 | 48 | /** 49 | * Processor for fields of type 'decimal'. 50 | * 51 | * @param Drupal\Core\Field\FieldItemList $field 52 | * Object representing a configurable field on an entity. 53 | * @param int $index 54 | * Delta of field being processed. 55 | * @param array $settings 56 | * Processor configuration and context. 57 | * 58 | * @return string 59 | * Processed value of field. 60 | */ 61 | function distill_distill_process_decimal(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 62 | $value = $field->getValue(); 63 | return $value[0]['value']; 64 | } 65 | 66 | /** 67 | * Processor for fields of type 'list_integer'. 68 | * 69 | * @param Drupal\Core\Field\FieldItemList $field 70 | * Object representing a configurable field on an entity. 71 | * @param int $index 72 | * Delta of field being processed. 73 | * @param array $settings 74 | * Processor configuration and context. 75 | * 76 | * @return string 77 | * Processed value of field. 78 | */ 79 | function distill_distill_process_list_integer(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 80 | $value = $field->getValue(); 81 | return $value[0]['value']; 82 | } 83 | 84 | /** 85 | * Processor for fields of type 'list_float'. 86 | * 87 | * @param Drupal\Core\Field\FieldItemList $field 88 | * Object representing a configurable field on an entity. 89 | * @param int $index 90 | * Delta of field being processed. 91 | * @param array $settings 92 | * Processor configuration and context. 93 | * 94 | * @return string 95 | * Processed value of field. 96 | */ 97 | function distill_distill_process_list_float(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 98 | $value = $field->getValue(); 99 | return $value[0]['value']; 100 | } 101 | 102 | /** 103 | * Processor for fields of type 'string'. 104 | * 105 | * @param Drupal\Core\Field\FieldItemList $field 106 | * Object representing a configurable field on an entity. 107 | * @param int $index 108 | * Delta of field being processed. 109 | * @param array $settings 110 | * Processor configuration and context. 111 | * 112 | * @return string 113 | * Processed value of field. 114 | */ 115 | function distill_distill_process_string(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 116 | $value = $field->getValue(); 117 | return $value[0]['value']; 118 | } 119 | 120 | /** 121 | * Processor for fields of type 'string_long'. 122 | * 123 | * @param Drupal\Core\Field\FieldItemList $field 124 | * Object representing a configurable field on an entity. 125 | * @param int $index 126 | * Delta of field being processed. 127 | * @param array $settings 128 | * Processor configuration and context. 129 | * 130 | * @return string 131 | * Processed value of field. 132 | */ 133 | function distill_distill_process_string_long(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 134 | $value = $field->getValue(); 135 | return $value[0]['value']; 136 | } 137 | 138 | /** 139 | * Processor for fields of type 'list_string'. 140 | * 141 | * @param Drupal\Core\Field\FieldItemList $field 142 | * Object representing a configurable field on an entity. 143 | * @param int $index 144 | * Delta of field being processed. 145 | * @param array $settings 146 | * Processor configuration and context. 147 | * 148 | * @return string 149 | * Processed value of field. 150 | */ 151 | function distill_distill_process_list_string(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 152 | $value = $field->getValue(); 153 | return $value[0]['value']; 154 | } 155 | 156 | /** 157 | * Processor for fields of type 'text'. 158 | * 159 | * @param Drupal\Core\Field\FieldItemList $field 160 | * Object representing a configurable field on an entity. 161 | * @param int $index 162 | * Delta of field being processed. 163 | * @param array $settings 164 | * Processor configuration and context. 165 | * 166 | * @return string 167 | * Processed value of field. 168 | */ 169 | function distill_distill_process_text(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 170 | $value = $field->getValue(); 171 | return $value[0]['value']; 172 | } 173 | 174 | /** 175 | * Processor for fields of type 'text_long'. 176 | * 177 | * @param Drupal\Core\Field\FieldItemList $field 178 | * Object representing a configurable field on an entity. 179 | * @param int $index 180 | * Delta of field being processed. 181 | * @param array $settings 182 | * Processor configuration and context. 183 | * 184 | * @return string 185 | * Processed value of field. 186 | */ 187 | function distill_distill_process_text_long(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 188 | $value = $field->getValue(); 189 | return $value[0]['value']; 190 | } 191 | 192 | /** 193 | * Processor for fields of type 'text_with_summary'. 194 | * 195 | * @param Drupal\Core\Field\FieldItemList $field 196 | * Object representing a configurable field on an entity. 197 | * @param int $index 198 | * Delta of field being processed. 199 | * @param array $settings 200 | * Processor configuration and context. 201 | * 202 | * @return string 203 | * Processed value of field. 204 | */ 205 | function distill_distill_process_text_with_summary(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 206 | $value = $field->getValue(); 207 | return array( 208 | 'text' => $value[0]['value'], 209 | 'summary' => $value[0]['summary'], 210 | ); 211 | } 212 | 213 | /** 214 | * Processor for fields of type 'boolean'. 215 | * 216 | * @param Drupal\Core\Field\FieldItemList $field 217 | * Object representing a configurable field on an entity. 218 | * @param int $index 219 | * Delta of field being processed. 220 | * @param array $settings 221 | * Processor configuration and context. 222 | * 223 | * @return string 224 | * Processed value of field. 225 | */ 226 | function distill_distill_process_boolean(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 227 | $value = $field->getValue(); 228 | return $value[0]['value'] == 0 ? FALSE : TRUE; 229 | } 230 | 231 | /** 232 | * Processor for fields of type 'file'. 233 | * 234 | * @param Drupal\file\Plugin\Field\FieldType\FileFieldItemList $field 235 | * Object representing a configurable field on an entity. 236 | * @param int $index 237 | * Delta of field being processed. 238 | * @param array $settings 239 | * Processor configuration and context. 240 | * 241 | * @return string 242 | * Processed value of field. 243 | */ 244 | function distill_distill_process_file(Drupal\file\Plugin\Field\FieldType\FileFieldItemList $field, $index, array $settings) { 245 | $value = $field->getValue(); 246 | $file = file_load($value[0]['target_id']); 247 | return file_create_url($file->getFileUri()); 248 | } 249 | 250 | /** 251 | * Processor for fields of type 'image'. 252 | * 253 | * @param Drupal\image\Plugin\Field\FieldType\ImageItem $field 254 | * Object representing a configurable field on an entity. 255 | * @param int $index 256 | * Delta of field being processed. 257 | * @param array $settings 258 | * Processor configuration and context. 259 | * 260 | * @return string 261 | * Processed value of field. 262 | */ 263 | function distill_distill_process_image(Drupal\image\Plugin\Field\FieldType\ImageItem $field, $index, array $settings) { 264 | $value = $field->getValue(); 265 | $file = file_load($value['target_id']); 266 | $uri = $file->getFileUri(); 267 | 268 | // If an image style is specified, get path for style. 269 | if (isset($settings['image_style'])) { 270 | $url = ImageStyle::load($settings['image_style'])->buildUrl($uri); 271 | } 272 | else { 273 | $url = file_create_url($file->getFileUri()); 274 | } 275 | 276 | return $url ? $url : NULL; 277 | } 278 | 279 | /** 280 | * Processor for fields of type 'entity_reference'. 281 | * 282 | * @param $field 283 | * Referenced entity object. 284 | * @param int $index 285 | * Delta of field being processed. 286 | * @param array $settings 287 | * Processor configuration and context. 288 | * 289 | * @return string 290 | * Processed value of field. 291 | */ 292 | function distill_distill_process_entity_reference($field, $index, array $settings) { 293 | $output = $field->id(); 294 | 295 | // If the settings array has specified that it wants fields of the 296 | // referenced entity to be returned. 297 | if (isset($settings['include_fields'])) { 298 | $processor = isset($settings['processor']) ? $settings['processor'] : new DistillProcessor(); 299 | $distiller = new Distill($field, $processor); 300 | 301 | // If include_fields is an array, and contains values, set those values. 302 | if (is_array($settings['include_fields']) && !empty($settings['include_fields'])) { 303 | foreach($settings['include_fields'] as $field_name => $field_settings) { 304 | // If no field settings were specified, use 305 | // field value instead of index as name. 306 | if (is_int($field_name)) { 307 | $field_name = $field_settings; 308 | $field_settings = array(); 309 | } 310 | $distiller->setField($field_name, $field_settings); 311 | } 312 | } 313 | 314 | // If include_fields is a boolean and is set to TRUE, include all fields. 315 | elseif ($settings['include_fields'] === TRUE) { 316 | $distiller->setAllFields(); 317 | } 318 | 319 | $output = $distiller->getFieldValues(); 320 | } 321 | elseif (isset($settings['path']) && $settings['path'] === TRUE) { 322 | $output = $field->url(); 323 | } 324 | 325 | 326 | return $output; 327 | } 328 | 329 | /** 330 | * Processor for fields of type 'link'. 331 | * 332 | * @param Drupal\Core\Field\FieldItemList $field 333 | * Object representing a configurable field on an entity. 334 | * @param int $index 335 | * Delta of field being processed. 336 | * @param array $settings 337 | * Processor configuration and context. 338 | * 339 | * @return string 340 | * Processed value of field. 341 | */ 342 | function distill_distill_process_link(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 343 | $value = $field->getValue(); 344 | return array( 345 | 'path' => $value[0]['uri'], 346 | 'title' => $value[0]['title'], 347 | ); 348 | } 349 | 350 | /** 351 | * Processor for fields of type 'datetime'. 352 | * 353 | * @param Drupal\Core\Field\FieldItemList $field 354 | * Object representing a configurable field on an entity. 355 | * @param int $index 356 | * Delta of field being processed. 357 | * @param array $settings 358 | * Processor configuration and context. 359 | * 360 | * @return string 361 | * Processed value of field. 362 | */ 363 | function distill_distill_process_datetime(Drupal\datetime\Plugin\Field\FieldType\DateTimeFieldItemList $field, $index, array $settings) { 364 | $value = $field->getValue(); 365 | return $value[0]['value']; 366 | } 367 | 368 | /** 369 | * Processor for fields of type 'created'. 370 | * 371 | * @param Drupal\Core\Field\FieldItemList $field 372 | * Object representing a configurable field on an entity. 373 | * @param int $index 374 | * Delta of field being processed. 375 | * @param array $settings 376 | * Processor configuration and context. 377 | * 378 | * @return string 379 | * Processed value of field. 380 | */ 381 | function distill_distill_process_created(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 382 | $value = $field->getValue(); 383 | return $value[0]['value']; 384 | } 385 | 386 | /** 387 | * Processor for fields of type 'changed'. 388 | * 389 | * @param Drupal\Core\Field\FieldItemList $field 390 | * Object representing a configurable field on an entity. 391 | * @param int $index 392 | * Delta of field being processed. 393 | * @param array $settings 394 | * Processor configuration and context. 395 | * 396 | * @return string 397 | * Processed value of field. 398 | */ 399 | function distill_distill_process_changed(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 400 | $value = $field->getValue(); 401 | return $value[0]['value']; 402 | } 403 | 404 | /** 405 | * Processor for fields of type 'uuid'. 406 | * 407 | * @param Drupal\Core\Field\FieldItemList $field 408 | * Object representing a configurable field on an entity. 409 | * @param int $index 410 | * Delta of field being processed. 411 | * @param array $settings 412 | * Processor configuration and context. 413 | * 414 | * @return string 415 | * Processed value of field. 416 | */ 417 | function distill_distill_process_uuid(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 418 | $value = $field->getValue(); 419 | return $value[0]['value']; 420 | } 421 | 422 | /** 423 | * Processor for fields of type 'language'. 424 | * 425 | * @param Drupal\Core\Field\FieldItemList $field 426 | * Object representing a configurable field on an entity. 427 | * @param int $index 428 | * Delta of field being processed. 429 | * @param array $settings 430 | * Processor configuration and context. 431 | * 432 | * @return string 433 | * Processed value of field. 434 | */ 435 | function distill_distill_process_language(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 436 | $value = $field->getValue(); 437 | return $value[0]['value']; 438 | } 439 | 440 | /** 441 | * Processor for fields of type 'path'. 442 | * 443 | * @param Drupal\path\Plugin\Field\FieldType\PathFieldItemList $field 444 | * Object representing a configurable field on an entity. 445 | * @param int $index 446 | * Delta of field being processed. 447 | * @param array $settings 448 | * Processor configuration and context. 449 | * 450 | * @return string 451 | * Processed value of field. 452 | */ 453 | function distill_distill_process_path(Drupal\path\Plugin\Field\FieldType\PathFieldItemList $field, $index, array $settings) { 454 | $value = $field->getValue(); 455 | return $value[0]['value']; 456 | } 457 | 458 | /** 459 | * Processor for fields of type 'comment'. 460 | * 461 | * @param Drupal\comment\Plugin\Field\FieldType\CommentItem $field 462 | * Object representing a configurable field on an entity. 463 | * @param int $index 464 | * Delta of field being processed. 465 | * @param array $settings 466 | * Processor configuration and context. 467 | * 468 | * @return string 469 | * Processed value of field. 470 | */ 471 | function distill_distill_process_comment(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 472 | return $field->getValue(); 473 | } 474 | 475 | /** 476 | * Processor for fields of type 'email'. 477 | * 478 | * @param Drupal\Core\Field\FieldItemList $field 479 | * Object representing a configurable field on an entity. 480 | * @param int $index 481 | * Delta of field being processed. 482 | * @param array $settings 483 | * Processor configuration and context. 484 | * 485 | * @return string 486 | * Processed value of field. 487 | */ 488 | function distill_distill_process_email(Drupal\Core\Field\FieldItemList $field, $index, array $settings) { 489 | $value = $field->getValue(); 490 | return $value[0]['value']; 491 | } 492 | -------------------------------------------------------------------------------- /src/Distill.php: -------------------------------------------------------------------------------- 1 | entity = $entity; 37 | $this->type = $entity->getEntityTypeId(); 38 | $this->bundle = $entity->bundle(); 39 | $this->id = $entity->id(); 40 | $this->fieldable = method_exists($this->entity, 'getFieldDefinitions'); 41 | 42 | // If this is not a fieldable entity, there's no need for a processor. 43 | // Just set $this->value to the id. 44 | if (!$this->fieldable) { 45 | $this->values = array('target_id' => $this->id); 46 | return; 47 | } 48 | 49 | // Load DistillProcessor. 50 | if ($processor && get_parent_class($processor) === 'DistillProcessor') { 51 | $this->processor = $processor; 52 | } 53 | else { 54 | $this->processor = new DistillProcessor(); 55 | } 56 | 57 | // Define which fields and field types can/cannot be processed. 58 | $this->setProcessableFieldsAndTypes(); 59 | 60 | // If language is passed in, set class language. 61 | if ($language) { 62 | $this->language = $language; 63 | } 64 | } 65 | 66 | /** 67 | * Determine which field types can be processed. 68 | */ 69 | protected function setProcessableFieldsAndTypes() { 70 | // Loop through fields and check for processability. 71 | foreach ($this->entity->getFieldDefinitions() as $field_name => $field) { 72 | $info = $field->getFieldStorageDefinition(); 73 | $type = $info->getType(); 74 | 75 | // Check to see if processor can process field of this type. 76 | $function_base_name = 'process' . $this->machineNameToCamelCase($type) . 'Type'; 77 | $this->processableFieldTypes[$type] = method_exists($this->processor, $function_base_name); 78 | 79 | // Check to see if processor has a function to process this field. 80 | $function_base_name = 'process' . $this->machineNameToCamelCase($field_name) . 'Field'; 81 | $this->processableFields[$field_name] = method_exists($this->processor, $function_base_name); 82 | } 83 | } 84 | 85 | /** 86 | * Builds a string that corresponds with the name of an extraction function. 87 | * 88 | * @param string $machine_name 89 | * Underscore-separated machine name of a field or field type. 90 | * 91 | * @return string 92 | * Camel Case version of the passed in machine name. 93 | */ 94 | protected function machineNameToCamelCase($machine_name) { 95 | // Turn into an underscored function. 96 | $function_name = $this->machineNameToUnderscore($machine_name); 97 | // Replace _ with ' ' so that words can be capitalized. 98 | $function_name = str_replace('_', ' ', $function_name); 99 | // Capitalize words. 100 | $function_name = ucwords($function_name); 101 | // Remove spaces. 102 | $function_name = str_replace(' ', '', $function_name); 103 | 104 | return $function_name; 105 | } 106 | 107 | /** 108 | * Builds a string that corresponds with the name of an extraction hook. 109 | * 110 | * @param string $machine_name 111 | * Underscore-separated machine name of a field or field type. 112 | * 113 | * @return string 114 | * Underscore version of the passed in machine name. 115 | */ 116 | protected function machineNameToUnderscore($machine_name) { 117 | // Remove >. 118 | $function_name = str_replace('>', '', $machine_name); 119 | // Replace < with _ 120 | $function_name = str_replace('<', '', $function_name); 121 | 122 | return $function_name; 123 | } 124 | 125 | /** 126 | * Adds a field value to the $this->values array. 127 | * 128 | * @param string $name 129 | * Name of field that should be added to field values array. 130 | * @param string $property_name 131 | * Name of property that will hold the field's value. 132 | * @param string $settings 133 | * Processor configuration and context. 134 | */ 135 | public function setField($name, $property_name = NULL, $settings = array()) { 136 | // If this entity isn't fieldable, don't add fields. 137 | if (!$this->fieldable) { 138 | return NULL; 139 | } 140 | 141 | // If field doesn't exist on entity, don't add it. 142 | if (!$this->entity->hasField($name) || $this->entity->{$name}->isEmpty()) { 143 | return NULL; 144 | } 145 | 146 | // Get information about this field that is needed to 147 | // process it's values later on. 148 | $field = $this->entity->{$name}; 149 | $info = $field->getFieldDefinition(); 150 | $type = $info->getType(); 151 | $isMultiple = FALSE; 152 | 153 | // If this field is a base field or an entity field, these properties 154 | // are extracted differently. 155 | if (get_class($info) === 'Drupal\Core\Field\BaseFieldDefinition') { 156 | $isMultiple = $info->isMultiple(); 157 | } 158 | else { 159 | $isMultiple = $field->count() > 1 ? TRUE : FALSE; 160 | } 161 | 162 | // Default $property_name to $name. 163 | if (!$property_name) { 164 | $property_name = $name; 165 | } 166 | 167 | // Start an array of field values. 168 | $field_values = array(); 169 | 170 | // Calls proper field processing function. 171 | // CodeSniffer ignored here because it doesn't 172 | // understand any sort of lexical scoping. 173 | // @codingStandardsIgnoreStart 174 | $process_field = function($type, $field, $index) use ($settings, $name) { 175 | // If there's a field name function, use it. 176 | if ($this->processableFields[$name]) { 177 | $function_name = 'process' . $this->machineNameToCamelCase($name) . 'Field'; 178 | } 179 | // If there's no field name function, but a type name function, use it. 180 | elseif ($this->processableFieldTypes[$type]) { 181 | $function_name = 'process' . $this->machineNameToCamelCase($type) . 'Type'; 182 | } 183 | // If no field type or name function, implement processor hook function. 184 | else { 185 | $function_name = 'distill_process_' . $this->machineNameToUnderscore($type); 186 | $values = \Drupal::moduleHandler()->invokeAll($function_name, [$field, $index, $settings]); 187 | if (empty($values)) { 188 | return NULL; 189 | } 190 | else { 191 | // If $values[0] is empty, but still has value, just return. 192 | if (!isset($values[0])) { 193 | return $values; 194 | } 195 | 196 | return $values[0]; 197 | } 198 | } 199 | 200 | return $this->processor->{$function_name}($field, $index, $settings); 201 | }; 202 | 203 | // If multivalue field, loop through and extract values. 204 | if ($isMultiple) { 205 | // Decide on iterator function name. This changes based on field type. 206 | $iterator_name = 'getIterator'; 207 | if (get_class($field) === 'Drupal\Core\Field\EntityReferenceFieldItemList') { 208 | $iterator_name = 'referencedEntities'; 209 | } 210 | // Loop through and process fields. 211 | foreach($field->{$iterator_name}() as $index => $field_item) { 212 | $field_values[] = $process_field($type, $field_item, $index); 213 | } 214 | } 215 | // If single value field, extract single value. 216 | else { 217 | $field_values = $process_field($type, $field, 0); 218 | } 219 | 220 | // Add field value to $this->fieldValues array. 221 | $this->values[$property_name] = $field_values; 222 | } 223 | // @codingStandardsIgnoreEnd 224 | 225 | /** 226 | * Adds all value of all fields on entity to the $this->values array. 227 | */ 228 | public function setAllFields() { 229 | // If this entity is not fieldable, skip. 230 | if (!$this->fieldable) { 231 | return; 232 | } 233 | 234 | foreach ($this->entityWrapper->getPropertyInfo() as $field_name => $field) { 235 | $this->setField($field_name); 236 | } 237 | } 238 | 239 | /** 240 | * Fetches and returns processed field values. 241 | */ 242 | public function getFieldValues() { 243 | return $this->values; 244 | } 245 | } 246 | -------------------------------------------------------------------------------- /src/DistillProcessor.php: -------------------------------------------------------------------------------- 1 | systemFieldTypes = array_keys(\Drupal::service('plugin.manager.field.field_type')->getDefinitions()); 17 | } 18 | } 19 | --------------------------------------------------------------------------------