I've created a block via my own custom module.

The block configuration page (/admin/structure/block/manage/jssorsliderblock) allows the adding and removing of files (images), to a particular folder. These images are utilised by the block when it's displayed.

My problem is that clicking the 'Save changes' button, the file is correctly uploaded to the specified folder, however Drupal doesn't pick up the changes. Clearing the caches fixes this.

I currently just upload the files using an upload form field, which may not officially register the file with Drupal. If this is the case, then maybe that's why Drupal doesn't realise a file has been added to the folder.

SOLUTIONS?

1) Do I need to flush caches programatically when the 'Save changes' button is clicked? If so can I just flush the caches I need (i.e. the file caches)? How do I do that?
2) Is there a better way of uploading the files, so that Drupal doesn't need it's caches clearing? (maybe there's a better way).

I saw this code elsewhere in a core module (/core/modules/forum/src/Plugin/Block/ForumBlockBase.php):

  /**
   * {@inheritdoc}
   */
  public function getCacheContexts() {
    return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    return Cache::mergeTags(parent::getCacheTags(), ['node_list']);
  }

Do I need something like that? Although these seem to just register what needs changing in that particular module, when the cache is cleared from outside (i.e. passive connection). I need it to be active, i.e. when changes are made, the cache is cleared immediately for the items that have changed (in this case files being added to the public file space).

Thanks.

Comments

Jaypan’s picture

Drupal 8 caches render arrays, and until the cache is cleared for that render array (or all caches), the code will not update. You can clear the cache for the given render array (in your case, a block)

For example, I recently created a page that displays images from an instagram feed on the site. I used the getCacheTags() in my block plugin as follows:

public function getCacheTags()
{
	return Cache::mergeTags(parent::getCacheTags(), ['instagram_stream']);
}

So the relevant cache tag is: instagram_stream

I have a cron run that pulls the stream info from instagram on cron runs. If new images are found, I then clear the block cache (and the page cache that uses the same stream info) with:

\Drupal::service('cache_tags.invalidator')->invalidateTags(['instagram_stream']);

So you will need to do two things:
1) Add cache tags to your block using getCacheTags()

2) Tie into the submit function on your block config page, and add a call that invalidates the cache tags for your block.

CatsFromStonehenge’s picture

In the end I put drupal_flush_all_caches(); into the Submit callback, which worked. The cache tags methods didn't seem to work for me, but then I don't fully understand yet. I even forced a cron, but still no change.

I don't feel my drupal_flush_all_caches() route, is the right way forward. I really need to tell Drupal the bear-minimum cache clearance required.

I need to read up on Drupal caching a lot more.

The code I tried was:

   public function blockSubmit($form, FormStateInterface $form_state) {
      $this->configuration['name'] = $form_state->getValue('jssor_simple_full_width_name');

      \Drupal::service('cache_tags.invalidator')->invalidateTags(['jssor_simple_full_width_files']);
   }

   public function getCacheTags() {
      return Cache::mergeTags(parent::getCacheTags(), ['jssor_simple_full_width_files']);
   }

However it was only the following that worked:

   public function blockSubmit($form, FormStateInterface $form_state) {
      $this->configuration['name'] = $form_state->getValue('jssor_simple_full_width_name');

      drupal_flush_all_caches();
   }
CatsFromStonehenge’s picture

Unfortunately it turns out that the drupal_flush_all_caches() call doesn't consistently clear the cache for me. Like I said, I need to do a lot more research on Drupal 8's caching system, as it relates to module development.

Jaypan’s picture

The code you showed was correct, however you have to note that it will not work until you clear the cache once, as the original build would not have had the cache tags applied in the cache. Try using that code again, but clear your cache.

CatsFromStonehenge’s picture

Thanks.

I couldn't get this consistently working in the end. However I think it's because I didn't officially register the files with Drupal. The files were being uploaded by a 'file upload' (managed_file) user interface element. This will upload the file to the specified directory within Drupal, but I am not sure that it officially registers the file with Drupal.

Although clearing caches (drush cr, for example) will tell Drupal to scan directories for changes to files (new or otherwise).

I think I've found a better way to achieve what I need to do. The alternative is for the user to create some content (via a specified content type). I'm then hoping to be able to parse and display this content type from within my block code.

hkirsman’s picture

Thank you, Jaypan, for the getCacheTags() code! Saved my day!

hunde.keba’s picture

I defined getCacheTags() inside my custom block and created a service to clear the cache using invalidateTags()

public function getCacheTags()
{
	return Cache::mergeTags(parent::getCacheTags(), ['instagram_stream']);
}