0

I have a block with a function getParts() which is called from a template. This function does a bunch of queries and returns an array of data. I need to make it so if it does not return any data, a 404 is generated.

I was able to successfully do this by injecting the block into the controller's __construct and then have code in the controller like:

public function execute()
{
    $resultPage = $this->resultPageFactory->create();

    // If there were no parts returned by the parts block then redirect to a 404
    if (count($this->myBlock->getParts()) === 0) {
        $resultForward = $this->resultForwardFactory->create();
        $resultForward->forward('noroute');
        return $resultForward;
    }

    return $resultPage;
}

All this works correctly, however, that getParts() function takes a while to run so I modified the block's getParts() to be something like:

    if (is_array($this->partsData)) {
        return $this->partsData;
    }
    else {
        // My time intensive code here
    }

So in theory this should cache the data so getParts() should only do all its lookups once, then on the second call to getParts() it will just return what it previously retrieved and stored in $this->partsData.

This caching isn't working, however. It looks like the controller is calling the block's function first, then the template is calling it later, but I think the block is really being created twice, once by the controller and once by the template, so when $this->partsData is checked it is empty both times.

How can I make it so the controller is sharing the same block object, so when getParts() is called the second time it doesn't have to do this lookup? Or, if there is some other way to generate a 404 from the block that could also work.

1 Answer 1

1

I understand that you have some concerns about variable definitions and their behaviour in your code.

When you define a variable as "protected" within a class, it means that the variable can only be accessed within that class and its subclasses. However, this has no direct relation to whether the variable is cacheable or not.

In your code, when you create a new object of the class, the variable in question will be initialized as empty by default. The specific behaviour of the variable, such as caching or data retrieval, depends on the implementation within the class and how it is used.

It seems that you have a controller that creates an object of the "block" class. This object will initially have an empty variable. The controller then executes your code to retrieve data. Subsequently, you use this "block" object in the layout to retrieve data. If the variable in the "block" object is not empty, the layout creates another object of the "block" class, with all the class definitions, and executes the function body.

You can use below solution,

You should apply the redirect logic within your block class instead of your controller.

<?php

// ...................

public function __construct(
    \Magento\Framework\App\Action\Context $context,
    \Magento\Framework\UrlInterface $url
)
{
    $this->context = $context;
    $this->response = $context->getResponse();
    $this->url = $url;
}

// ...................

public function getParts() {
    $this->partsData = "My time intensive code here";     
    if (empty($this->partsData)) {
        $norouteUrl = $this->url->getUrl('noroute');
        $this->response->setRedirect($norouteUrl);
        return;
    }
    return $this->partsData;
}

// ...................

Remove creating object and calling method from the controller, As per above code your block will be redirect to 404 if record is empty.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.