1

I've got a block that relies on a fairly flaky third party service to get data to render so, when it does encounter a problem, I'd like to display an error message, rather than throw an exception and not render the page.

Easy enough to do until you come to block/page caching. The data has a long lifetime so, when found, it's fine to cache everything. When it isn't, though, the page is cached with the error message in place. As such, I need to tell the CMS not to save the block or page output to the cache.

Example code (within block controller):

public function view() {
    try {
        $this->set ('data', $this->getData());

    } catch (\Exception $e) {
        \Log::addError ('Blockname Error: '.$e->getMessage(), [$e]);
        $this->render ('error');
    }
}

Within the catch block I've tried both $this->btCacheBlockOutput = true; and \Cache::disableAll(); but neither works. Is there a way to tell C5 not to cache anything on the current request?

Andrew Dinmore
  • 804
  • 7
  • 14

1 Answers1

0

The BlockController in the concrete folder has these protected variables set as standard :

protected $btCacheBlockRecord = true;
protected $btCacheBlockOutput = false;
protected $btCacheBlockOutputOnPost = false;
protected $btCacheBlockOutputForRegisteredUsers = false;

So if you set all these on your block controller.php on false, it should not cache your block.

class Controller extends BlockController
{
  protected $btCacheBlockRecord = false;
  protected $btCacheBlockOutput = false;
  protected $btCacheBlockOutputOnPost = false;
  protected $btCacheBlockOutputForRegisteredUsers = false;
  public function view(){
    .....

This will disable the caching of the block (even if the third party connection succeeds).

A different solution is to save the data received from the third party in the database (for example as a json string) and load the data from the database if the third party connection fails... if the third party connection succeeds, you can update the record in the database.

Depending of the answer of the third party service you can set the conditions. Example:

//service returns on OK:
//array('status' => 'ok')
//service returns on NOT OK:
//array('status' => 'nok')

public function view() {
    $data = $this->getData();
    if($data['status'] == 'ok'){
       //save data to database in a config value using concrete Config class
       $configDatabase = \Core::make('config/database');
       $configDatabase->save('thirdpartyanswer', $data);
       $this->set('data', $data);
    }else{
       //getData function returned error or nok status
       //get data from concrete Config class
       $configDatabase = \Core::make('config/database');
       if($configDatabase->get('thirdpartyanswer')) != ''){
          //set data as "old" data from config
          $this->set('data', $configDatabase->get('thirdpartyanswer'));
       }else{
          //no data in config -> set error and nothing else
          $this->set('error', 'An error occured contacting the third party');
       }
    }
}

(The code above has not been tested)
More information on storing config values :
https://documentation.concrete5.org/developers/packages/storing-configuration-values

* Edit *

A third option is to purge the cache for that specific page if the call fails.

At the top of your blockcontroller :

use \Concrete\Core\Cache\Page\PageCache;
use Page;

In the 'if' when the call to the API fails :

$currentPage = Page::getCurrentPage();
$cache = PageCache::getLibrary();
$cache->purge($currentPage);

Found at : https://www.concrete5.org/community/forums/5-7-discussion/programmatically-expiring-pages-from-cache

Jozzeh
  • 841
  • 10
  • 28
  • Thanks, but that doesn't answer the question. The block is used on high traffic pages where full page caching is really required. I'm already saving the data in the "expensive" (disk) cache, which is perfect for this, but doesn't help the page caching problem. – Andrew Dinmore Feb 05 '17 at 12:41
  • I've edited my response, see 'third' option. I have tested if the page still loads, so the code is valid. – Jozzeh Feb 06 '17 at 08:01
  • If purging the page from the cache like that prevents the output currently being rendered from being cached, that's a good start but, from a quick test, I'm still seeing the old block output. Presumably this would be coming from the block output cache, calling the relevant block object's refreshBlockOutputCache method in the error handling doesn't seem to help. Maybe manually populating the block's cacheSettings object at this point will help, I'll have to have a play later when I've time. – Andrew Dinmore Feb 07 '17 at 13:40