Using the File and Image fields

In order to demonstrate how to work with managed files, we will go back to our product entity importer and bring in some images for each product. However, in order to store them, we need to create a field on the Product entity. This will be an image field.

Instead of creating this field through the UI and attaching it to a bundle, let's do it the programmatic way and make it a base field (available on all bundles). We won't need to do anything complex; for now we are only interested in a basic field that we can use to store the images we bring in from the remote API. It can look something like this:

$fields['image'] = BaseFieldDefinition::create('image') 
  ->setLabel(t('Image')) 
  ->setDescription(t('The product image.')) 
  ->setDisplayOptions('form', array( 
    'type' => 'image_image', 
    'weight' => 5, 
  ));  

If you remember from Chapter 6, Data Modeling and Storage, and Chapter 7, Your Own Custom Entity and Plugin Types, we are creating a base field definition that, in this case, is of the type image. This is the FieldType plugin ID of the ImageItem field type. So that is where we need to look and see what kind of field and storage options we may have. For example, we can have a file extension limitation (which by default contains png, gif, jpg, and jpeg) and things like alt and title attributes, as well as image dimension configuration. Do check out ImageItem to get an idea of the possible storage and field settings. However, we are fine with the defaults in this case so we don't even have any field settings.

Another interesting thing to notice is that ImageItem extends the FileItem field type, which is a standalone FieldType plugin that we can use. However, it is more generic and lends itself for use with any kind of file upload situation. Since we are dealing with images, we might as well take advantage of the specific field type.

For the moment, we do not configure our image field to have any kind of display. We'll look into that a bit later. However, we do specify the widget it should use on the entity form, namely the FieldWidget plugin with the ID of image_image. This maps to the default ImageWidget field widget. But again, we are fine with the setting defaults, so we don't specify anything extra.

With this, our field definition is done. To have Drupal create the necessary database tables, we need to run the Drush command:

drush entity-update  

Now let's create the interface methods for easily accessing and setting the images:

/** 
 * Gets the Product image. 
 * 
 * @return \Drupal\file\FileInterface 
 */ 
public function getImage(); 
 
/** 
 * Sets the Product image. 
 * 
 * @param int $image 
 * 
 * @return \Drupal\products\Entity\ProductInterface 
 *   The called Product entity. 
 */ 
public function setImage($image);  

The getter method is supposed to return a FileInterface object (which is the actual File entity), while the setter is supposed to receive the ID (fid) of the File entity to save. As for the implementations, it should not be anything new to us:

/** 
 * {@inheritdoc} 
 */ 
public function getImage() { 
  return $this->get('image')->entity; 
} 
 
/** 
 * {@inheritdoc} 
 */ 
public function setImage($image) { 
  $this->set('image', $image); 
  return $this; 
}  

With this, we are ready to proceed with the import of images from the remote API.

For taking advantage of the media management power in Drupal 8, instead of Image or File fields, you'd create entity reference fields to Media entities. And on the latter you'd create these fields. As such, Media entities basically wrap the File entities to provide some additional functionality and expose them to all the goodies of media management. For now, we work directly with these field types to learn about low-level file handling without the overhead of Media.