Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

500 Error when saving categories with invalid layout update xml - Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function getCategorySearchQuery() on array #1347

Closed
harrigo opened this issue Mar 11, 2019 · 10 comments
Assignees

Comments

@harrigo
Copy link

harrigo commented Mar 11, 2019

Some categories throw 500 error upon saving from admin:

[11-Mar-2019 16:45:56 UTC] PHP Fatal error: Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function getCategorySearchQuery() on array in /home/sites/magento/testing_html/vendor/magento/module-ui/Component/Wrapper/UiComponent.php on line 0

I have seen similar issues listed however flat category does not make a difference in this instance and feel they may have been on older versions and later fixed.

Preconditions

Magento Version : CE 2.2.7

ElasticSuite Version : "smile/elasticsuite": "^2.6.0"

Environment : Developer

Steps to reproduce

  1. Modify a category on backend
  2. Have invalid xml like below within layout update xml:
<referenceBlock name="page.main.title">
               <action method="setPageTitle">
                  <argument translate="true" name="title" xsi:type="string">Custom Category Title</argument>
               </action>
</referenceBlock>
  1. Save
  2. Errors shows

Expected result

  1. Modify a category on backend.
  2. Have invalid xml like below within layout update xml:
<referenceBlock name="page.main.title">
               <action method="setPageTitle">
                  <argument translate="true" name="title" xsi:type="string">Custom Category Title</argument>
               </action>
</referenceBlock>
  1. Save
  2. Notified that Invalid XML is present so can be corrected

Further debugging shows that the error seems to occur in Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin where on save of categories on my testing site the getCategoryFilterParam() method seems to cause this at $category->getVirtualRule()->getCategorySearchQuery($category); dump($category->getVirtualRule()); showing completely different results on different instances.

dump($category->getVirtualRule(), true); shows:

array:1 [▼
  "conditions" => array:1 [▼
    1 => array:4 [▼
      "type" => "Smile\ElasticsuiteVirtualCategory\Model\Rule\Condition\Combine"
      "aggregator" => "all"
      "value" => "1"
      "new_child" => ""
    ]
  ]
]

Which is not correct looking at the same results on admin category page load and when saving on my working instances:

Rule {#1967 ▼
  -queryFactory: QueryFactory {#1511 ▶}
  -productConditionsFactory: ProductFactory {#1494 ▶}
  -categoryFactory: CategoryFactory {#1368 ▶}
  -categoryCollectionFactory: CollectionFactory {#1512 ▶}
  -queryBuilder: QueryBuilder {#1966 ▶}
  -storeManager: StoreManager {#185 ▶}
  #conditionsFactory: CombineFactory {#1495 ▶}
  #elementName: null
  #_conditions: Combine {#1970 ▶}
  #_actions: null
  #_form: null
  #_isDeleteable: true
  #_isReadonly: false
  #serializer: Json {#151}
  #_formFactory: FormFactory {#1496 ▶}
  #_localeDate: Timezone {#786 ▼
    #_allowedFormats: array:4 [▶]
    #_scopeType: "default"
    #_scopeResolver: Store {#90 ▶}
    #_dateTime: DateTime {#162}
    #_defaultTimezonePath: "general/locale/timezone"
    #_scopeConfig: Config {#126 ▶}
    #_localeResolver: Resolver {#727 ▶}
  }
  #extensionAttributesFactory: ExtensionAttributesFactory {#252 ▼
    #objectManager: ObjectManager {#44}
    -classInterfaceMap: []
  }
  #extensionAttributes: null
  #customAttributeFactory: AttributeValueFactory {#253 ▶}
  #customAttributesCodes: null
  #customAttributesChanged: true
  #_eventPrefix: "core_abstract"
  #_eventObject: "object"
  #_idFieldName: "id"
  #_hasDataChanges: true
  #_origData: null
  #_isDeleted: false
  #_resource: null
  #_resourceCollection: null
  #_resourceName: null
  #_collectionName: null
  #_cacheTag: false
  #_dataSaveAllowed: true
  #_isObjectNew: null
  #_validatorBeforeSave: null
  #_eventManager: Proxy {#209 ▶}
  #_cacheManager: Proxy {#154 ▶}
  #_registry: Registry {#165 ▶}
  #_logger: Monolog {#129 ▶}
  #_appState: Interceptor {#87 ▶}
  #_actionValidator: Proxy {#236 ▶}
  #storedData: []
  #_data: array:1 [▶]
}

Seems similar to following issues:

#187
#205

@martijnrmediact
Copy link

We are encountering the same issue after using ElasticSuite.

@harrigo
Copy link
Author

harrigo commented Mar 14, 2019

Im not gonna pretend like a fully know what is going on here but I changed the category object temporarily to pull the category from repo rather than the $category object currently used and my actual error was shown I believe.

Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin

    private $categoryRepository;
	 
    public function __construct(
        ...
	\Magento\Catalog\Model\CategoryRepository $categoryRepository
    ) {
        ...
	$this->categoryRepository = $categoryRepository;
    }

    private function getCategoryFilterParam(CategoryInterface $category)
    {
        $filterParam = $category->getId();

        if ($category->getVirtualRule()) { // Implicit dependency to Virtual Categories module.
	    //grab category
            $category = $this->categoryRepository->get($category->getId());
            $category->setIsActive(true);
            $filterParam = $category->getVirtualRule()->getCategorySearchQuery($category);
        }

        return $filterParam;
    }

Maybe Magento changed validation with the layout update xml there as was not witnessing errors on previous versions however.... Some error checking is failing when this module is in place that stopped me from seeing the actual error about the layout update xml being invalid.

My issue:

Categories with Layout Update XML that is incorrect seem to throw a 500 error rather than showing an actual error. In my case:

Element 'referenceBlock': This element is not expected. Expected is one of ( referenceContainer, container, update, move, head, body ). Line: 1

My XML was:

<referenceBlock name="page.main.title">
               <action method="setPageTitle">
                  <argument translate="true" name="title" xsi:type="string">Custom Category Title</argument>
               </action>
</referenceBlock>

I changed the Layout Update XML to below:

<referenceContainer name="content">
<referenceBlock name="page.main.title">
               <action method="setPageTitle">
                  <argument translate="true" name="title" xsi:type="string">Cleaning Supplies, Hygiene Supplies, Facilities Supplies</argument>
               </action>
</referenceBlock>
</referenceContainer>

Category seems to save ok now once changed that Layout Update XML to be correct.

@martijnrmediact maybe check your XML for something like that or try the little mod I did temporarily to get the actual error.

@harrigo harrigo changed the title Cannot save some categories - Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function getCategorySearchQuery() on array 500 Error when saving categories with invalid layout update xml - Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function getCategorySearchQuery() on array Mar 14, 2019
@romainruaud
Copy link
Collaborator

Most probably a duplicate of #1345

Do you have any third-party or custom modules that are actually extending/overriding the legacy Category module ?

@harrigo
Copy link
Author

harrigo commented Mar 14, 2019

I have had a look and cannot see anything that is extending or overriding Magento\Catalog\Model\Category which is what seems to be the problem in that question posted and it does seem to be the $category object that is not as expected. I ran grep -r "Magento/\Catalog/\Model/\Category" accross app/code and vendor folders which returned no results from custom modules.

@harrigo
Copy link
Author

harrigo commented Mar 14, 2019

This is my trace I cannot see anything other than elasticsearch and legacy magento code in there:

#0 Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin->getCategoryFilterParam() called at [/var/www/magento/public_html/vendor/smile/elasticsuite/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php:240] 
#1 Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin->getAttributes() called at [/var/www/magento/public_html/vendor/smile/elasticsuite/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php:133] 
#2 Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin->getFilterableAttributeList() called at [/var/www/magento/public_html/vendor/smile/elasticsuite/src/module-elasticsuite-catalog/Plugin/Ui/Category/Form/DataProviderPlugin.php:116] 
#3 Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin->aroundGetData() called at [/var/www/magento/public_html/vendor/magento/framework/Interception/Interceptor.php:135] 
#4 Magento\Catalog\Model\Category\DataProvider\Interceptor->Magento\Framework\Interception\{closure}() called at [/var/www/magento/public_html/vendor/smile/elasticsuite/src/module-elasticsuite-virtual-category/Plugin/Catalog/Category/DataProviderPlugin.php:83] 
#5 Smile\ElasticsuiteVirtualCategory\Plugin\Catalog\Category\DataProviderPlugin->aroundGetData() called at [/var/www/magento/public_html/vendor/magento/framework/Interception/Interceptor.php:135] 
#6 Magento\Catalog\Model\Category\DataProvider\Interceptor->Magento\Framework\Interception\{closure}() called at [/var/www/magento/public_html/vendor/magento/framework/Interception/Interceptor.php:153] 
#7 Magento\Catalog\Model\Category\DataProvider\Interceptor->___callPlugins() called at [/var/www/magento/public_html/generated/code/Magento/Catalog/Model/Category/DataProvider/Interceptor.php:52] 
#8 Magento\Catalog\Model\Category\DataProvider\Interceptor->getData() called at [/var/www/magento/public_html/vendor/magento/module-ui/Component/Form.php:69] 
#9 Magento\Ui\Component\Form->getDataSourceData() called at [/var/www/magento/public_html/vendor/magento/framework/View/Element/UiComponent/Context.php:227] 
#10 Magento\Framework\View\Element\UiComponent\Context->getDataSourceData() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout/Generic.php:75] 
#11 Magento\Framework\View\Layout\Generic->build() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout/Generator/Structure.php:46] 
#12 Magento\Framework\View\Layout\Generator\Structure->generate() called at [/var/www/magento/public_html/vendor/magento/module-ui/TemplateEngine/Xhtml/Result.php:84] 
#13 Magento\Ui\TemplateEngine\Xhtml\Result->appendLayoutConfiguration() called at [/var/www/magento/public_html/vendor/magento/module-ui/TemplateEngine/Xhtml/Result.php:106] 
#14 Magento\Ui\TemplateEngine\Xhtml\Result->__toString() called at [/var/www/magento/public_html/vendor/magento/module-ui/Component/Wrapper/UiComponent.php:73] 
#15 Magento\Ui\Component\Wrapper\UiComponent->_toHtml() called at [/var/www/magento/public_html/vendor/magento/framework/View/Element/AbstractBlock.php:667] 
#16 Magento\Framework\View\Element\AbstractBlock->toHtml() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:570] 
#17 Magento\Framework\View\Layout->_renderUiComponent() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:531] 
#18 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] #
19 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#20 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#21 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#22 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#23 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#24 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#25 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#26 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#27 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#28 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#29 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#30 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#31 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#32 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#33 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#34 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#35 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#36 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#37 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#38 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#39 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#40 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#41 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#42 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#43 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#44 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#45 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#46 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#47 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#48 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206]
#49 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#50 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#51 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#52 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#53 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#54 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#55 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#56 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:585] 
#57 Magento\Framework\View\Layout->_renderContainer() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:535] 
#58 Magento\Framework\View\Layout->renderNonCachedElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:206] 
#59 Magento\Framework\View\Layout\Interceptor->renderNonCachedElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:488] 
#60 Magento\Framework\View\Layout->renderElement() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:193] 
#61 Magento\Framework\View\Layout\Interceptor->renderElement() called at [/var/www/magento/public_html/vendor/magento/framework/View/Layout.php:954] 
#62 Magento\Framework\View\Layout->getOutput() called at [/var/www/magento/public_html/generated/code/Magento/Framework/View/Layout/Interceptor.php:492] #63 Magento\Framework\View\Layout\Interceptor->getOutput() called at [/var/www/magento/public_html/vendor/magento/framework/View/Result/Page.php:257] 
#64 Magento\Framework\View\Result\Page->render() called at [/var/www/magento/public_html/vendor/magento/framework/View/Result/Layout.php:170] 
#65 Magento\Framework\View\Result\Layout->renderResult() called at [/var/www/magento/public_html/generated/code/Magento/Backend/Model/View/Result/Page/Interceptor.php:193] 
#66 Magento\Backend\Model\View\Result\Page\Interceptor->renderResult() called at [/var/www/magento/public_html/vendor/magento/framework/App/Http.php:139] 
#67 Magento\Framework\App\Http->launch() called at [/var/www/magento/public_html/generated/code/Magento/Framework/App/Http/Interceptor.php:24] 
#68 Magento\Framework\App\Http\Interceptor->launch() called at [/var/www/magento/public_html/vendor/magento/framework/App/Bootstrap.php:257] 
#69 Magento\Framework\App\Bootstrap->run() called at [/var/www/magento/public_html/pub/index.php:37] 

@PieterCappelle
Copy link

PieterCappelle commented Mar 14, 2019

I'm having the same issue, very strange.
Fatal error: Method Magento\Ui\TemplateEngine\Xhtml\Result::__toString() must not throw an exception, caught Error: Call to a member function getCategorySearchQuery() on string in /home/x/magento2/vendor/magento/module-ui/Component/Wrapper/UiComponent.php on line 0

If I comment the following code in Smile\ElasticsuiteCatalog\Plugin\Ui\Category\Form\DataProviderPlugin, it works

` /**
* Return category filter param
*
* @param CategoryInterface $category Category.
*
* @return int|QueryInterface
*/
private function getCategoryFilterParam(CategoryInterface $category)
{
$filterParam = $category->getId();

    // if ($category->getVirtualRule()) { // Implicit dependency to Virtual Categories module.
    //     $category->setIsActive(true);

    //     $filterParam = $category->getVirtualRule()->getCategorySearchQuery($category);
    // }

    return $filterParam;
}`

@romainruaud romainruaud self-assigned this Mar 15, 2019
@romainruaud
Copy link
Collaborator

Ok, I took some time on this one.

My mistake, I did not understand previously the things related to submitting an invalid layout update.

So :

NOT reproduced on Magento 2.3

BUT I reproduce it exactly on Magento 2.2.x

So most probably, something has changed Magento side to better deal with these sort of errors. I'll see if we can provide a quickfix into Elasticsuite 2.6.x version. Probably the category don't get proper reload on such failure case.

Regards

@harrigo
Copy link
Author

harrigo commented Mar 15, 2019

Thanks Romain! I got myself out of trouble here but would be good to get an official fix rather than loading category from repo that I have done to fix this category not loading properly when errors shown.

@romainruaud
Copy link
Collaborator

Erratum : reproduced in Elasticsuite 2.6.x AND 2.7.x.

Appears to be due to the fact that when the form contains an error, previous data is set back to the current category as an array for the "virtual_rule" field, which causes this error.

Will dig more on this one.

Regards

@romainruaud
Copy link
Collaborator

Fixed by PR #1355

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants