Magento – skip function execution using before plugin

adminmagento2.2pluginredirectresponse

I'm overriding the controller Magento\User\Controller\Adminhtml\User\Validate::execute() using before-plugin so I can perform some checks before magento validate using this function. If certain condition met, I want to return an error response from my before-plugin and skip the execution of main execute action. For this, I write the code below.

<!-- app/code/[vendor]/[module]/etc/di.xml -->
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\User\Controller\Adminhtml\User\Validate">
        <plugin name="admin_user_validate_controller_plugin" type="[vendor]\[module]\Plugin\AdminUserValidateControllerPlugin" sortOrder="20"/>
    </type>
</config>

and here is my plugin.

namespace [vendor]\[module]\Plugin;

class AdminUserValidateControllerPlugin
{            
    public function beforeExecute(\Magento\User\Controller\Adminhtml\User\Validate $subject)
    {
        $response = new \Magento\Framework\DataObject();
        $response->setError(0);
        $errors = null;

        if([some_custom_validation_checks_return_false]) {
            $error = "some_error_message"; 
            $subject->messageManager->addError($error);

            $response->setError(1);
            $subject->_view->getLayout()->initMessages();
            $response->setHtmlMessage($subject->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
            $subject->getResponse()->representJson($response->toJson()); 
        }
    }
}

Question#1: I was expecting it to return my error message in response of ajax call of validation controller, but it redirects to admin_dashboard page with my error message. How can I make it correct so my plugin will respond.

Question#2: After responding via ajax, how can we make it so magento stop further execution of main function. Also can we achieve it? That is, can we exit/die further execution in before-plugin in a proper way?

Thank you.

Best Answer

Still not sure whether I can use plugin or not as per my functionality requirement. So as a workaround, I'm using preference. Would love to hear from someone the plugin_way of doing this. Preference way is as follow. Hope this helps someone.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">    
    <preference for="Magento\User\Controller\Adminhtml\User\Validate" type="[vendor]\[module]\Controller\Rewrite\Adminhtml\User\Validate" />
</config>

And the rewritten controller is as follow.

namespace [vendor]\[module]\Controller\Rewrite\Adminhtml\User;

class Validate extends \Magento\User\Controller\Adminhtml\User\Validate
{
    /**
     * AJAX customer validation action
     *
     * @return void
     */
    public function execute()
    {
        $response = new \Magento\Framework\DataObject();
        $response->setError(0);
        $errors = null;
        $userId = (int)$this->getRequest()->getParam('user_id');
        $data = $this->getRequest()->getPostValue();

        if([some_validation_criteria_fails]) {
            $err = "You error message";
            $errors[] = $err; 
        }else{

            try {
                /** @var $model \Magento\User\Model\User */
                $model = $this->_userFactory->create()->load($userId);
                $model->setData($this->_getAdminUserData($data));
                $errors = $model->validate();
            } catch (\Magento\Framework\Validator\Exception $exception) {
                /* @var $error Error */
                foreach ($exception->getMessages(\Magento\Framework\Message\MessageInterface::TYPE_ERROR) as $error) {
                    $errors[] = $error->getText();
                }
            }

        }

        if ($errors !== true && !empty($errors)) {
            foreach ($errors as $error) {
                $this->messageManager->addError($error);
            }
            $response->setError(1);
            $this->_view->getLayout()->initMessages();
            $response->setHtmlMessage($this->_view->getLayout()->getMessagesBlock()->getGroupedHtml());
        }

        $this->getResponse()->representJson($response->toJson());
    }

}
?>

This will return error message as per your validation scenario.

Related Topic