Attaching managed files to entities

Now that we have our product image field in place and we can store images, let's revisit our JSON response that contains the product data and assume it looks something like this now:

{ 
  "products" : [ 
    { 
      "id" : 1, 
      "name": "TV", 
      "number": 341, 
      "image": "tv.jpg" 
    }, 
    { 
      "id" : 2, 
      "name": "VCR", 
      "number": 123, 
      "image": "vcr.jpg" 
    } 
  ] 
}  

What's new is the addition of the image key for each product, which simply references a filename for the image that goes with the respective product. The actual location of the images is at some other path we need to include in the code.

Going back to our JsonImporter::persistProduct() method, let's delegate the handling of the image import to a helper method called handleProductImage(). We need to call this method both if we are creating a new Product entity and if we are updating an existing one (right before saving):

$this->handleProductImage($data, $product);  

And this is what the actual method looks like:

/** 
 * Imports the image of the product and adds it to the Product entity. 
 * 
 * @param $data 
 * @param DrupalproductsEntityProductInterface $product 
 */ 
private function handleProductImage($data, ProductInterface $product) { 
  $name = $data->image; 
  // This needs to be hardcoded for the moment. 
  $image_path = ''; 
  $image = file_get_contents($image_path . '/' . $name); 
  if (!$image) { 
    // Perhaps log something. 
    return; 
  } 
 
  /** @var DrupalfileFileInterface $file */ 
  $file = file_save_data($image, 'public://product_images/' . $name, FileSystemInterface::EXISTS_REPLACE); 
  if (!$file) { 
    // Something went wrong, perhaps log it. 
    return; 
  } 
 
  $product->setImage($file->id()); 
}  

And the new use statement at the top:

use DrupalproductsEntityProductInterface; 
use DrupalCoreFileFileSystemInterface;  

First, we get the name of the image. Then we construct the path to where the product images are stored. In this example, it's left blank, but if the example were to work, we'd have to add a real path there. I leave that up to you for now. If you want to test it out, create a local folder with some images and reference that.

Using the native file_get_contents() function, we load the data of the image from the remote environment into a string. We then pass this string to the file_save_data() function which saves a new managed file to the public filesystem. This function takes three parameters: the data to be saved, the URI of the destination, and a flag indicating what to do if a file with the same name already exists. You'll notice that we used the Drupal public:// stream wrapper to build the URI and we already know which folder this maps to.

As for the third parameter, we chose to replace the file in case one already exists. The alternative would have been to either use the EXISTS_RENAME or EXISTS_ERROR constants of the same interface. The first would have created a new file whose name would have gotten a number appended until the name became unique. The second would have simply not done anything and returned FALSE.

If all goes well, this function returns a File entity (that implements FileInterface) whose ID we can use in the Product image setter method. With that in place, we can synchronize also the individual product images.

If you run into issues after this, make sure you create the destination folder and have all the permissions in order in the public filesystem to allow the copy to take place properly. In the next section you'll learn about some helper functions you can use to better prepare with the destination folder.

Moreover, in our database, a record is created in the file_usage table to indicate that this file is being used on the respective Product entity.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset