I am creating a backend magento 2 module and when I specify in the layout file a custom block, it will show a blank page with this being added to the system.log
[2016-10-19 07:35:35] main.INFO: Cache file with merged layout: LAYOUT_adminhtml_STORE1_32fdcd7fcff058e6f791ea5b6050bd6b5 and handles default, widget_selectwidget_index: Please correct the XML data and try again. [] [] [2016-10-19 07:35:35] main.INFO: Cache file with merged layout: LAYOUT_adminhtml_STORE1_3a2e4822a98337283e39f7b60acf85ec9 and handles empty: Please correct the XML data and try again. [] [] [2016-10-19 07:35:35] main.CRITICAL: Broken reference: the 'logo' element cannot be added as child to 'header', because the latter doesn't exist [] [] [2016-10-19 07:35:35] main.CRITICAL: Broken reference: the 'global.search' element cannot be added as child to 'header', because the latter doesn't exist [] [] [2016-10-19 07:35:35] main.CRITICAL: Broken reference: the 'user' element cannot be added as child to 'header', because the latter doesn't exist [] []
.... etc etc etc ....
[2016-10-19 07:35:35] main.CRITICAL: Broken reference: the 'header.inner.right' tries to reorder itself towards 'header.inner.left', but their parents are different: 'header' and '' respectively. [] [] [2016-10-19 07:35:35] main.CRITICAL: Broken reference: the 'global.search' tries to reorder itself towards 'notification.messages', but their parents are different: 'header.inner.right' and '' respectively. [] [] [2016-10-19 07:35:35] main.INFO: Cache file with merged layout: LAYOUT_adminhtml_STORE1_36f1b068ec7ccf4878f9284dd1137afd1 and handles catalog_product_prices: Please correct the XML data and try again. [] []
If I specify my block class as class="Magento\Backend\Block\Template" then it will show the page with the correct template which leads me to think that there is no problem with the template or the rest of the module.
Here is the block (app/code/Vendor/Widget/Block/Adminhtml/SelectWidgetBlock.php) :
namespace Vendor\Widget\Block\Adminhtml;
use Magento\Backend\Block\Template;
class SelectWidgetBlock extends Template
{
public function __construct(Template\Context $context, array $data = [])
{
parent::__construct($context, $data);
}
public function greet()
{
return 'Hello world';
}
}
This is the layout file (app/code/Vendor/Widget/view/adminhtml/layout/widget_selectwidget_index.xml) :
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" layout="empty">
<head>
<title>
Widget
</title>
</head>
<body>
<referenceContainer name="content">
<block class="Vendor\Widget\Block\Adminhtml\SelectWidgetBlock" name="vendor_widget.select" template="Vendor_Widget::selectwidget.phtml"/>
</referenceContainer>
</body>
Now the phtml (app/code/Vendor/Widget/view/adminhtml/templates/selectwidget.phtml) :
<p>Here is the phtml file</p>
<?php echo $this->greet() ?>
Here is the controller just in case (app/code/Vendor/Widget/Controller/Adminhtml/SelectWidget/Index.php) :
namespace Vendor\Widget\Controller\Adminhtml\SelectWidget;
class Index extends \Magento\Backend\App\Action
{
protected $resultPageFactory;
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\View\Result\PageFactory $resultPageFactory
) {
parent::__construct($context);
$this->resultPageFactory = $resultPageFactory;
}
public function execute()
{
return $resultPage = $this->resultPageFactory->create();
}
}
If you have any idea, please !
I solved my problem by removing layout="empty" from my layout file.
Related
I am trying to create a custom block in the order confirmed email to add some information about a custom shipping method.
This is what I tried so far, but it doesn't show my block in the email.
In /app/code/moduleA/moduleB/view/frontend/layout folder I created sales_order_info_links.xml
<?xml version="1.0" encoding="UTF-8"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<block class="moduleA\moduleB\Block\moduleApickuppointemail" name="moduleApickuppointemail" before="items" template="moduleA_moduleB::moduleApickuppointemail.phtml" />
</body>
</page>
In /app/code/moduleA/moduleB/Block folder I created moduleApickuppointemail.php
<?php
namespace moduleA\moduleB\Block;
class moduleApickuppointemail extends \Magento\Framework\View\Element\Template
{
public function __construct(\Magento\Framework\View\Element\Template\Context $context)
{
parent::__construct($context);
}
public function sayHello()
{
return __('Hello World');
}
}
In /app/code/moduleA/moduleB/view/frontend/templates I created moduleApickuppointemail.phtml
<?php
/**
* #var \moduleA\moduleB\Block\moduleApickuppointemail $block
*/
echo $block->sayHello();
But my code isn't working, nothing is shown in the email.
Can some please guide me on how to add custom blocks in the order confirmed email (shipping section if possible) using a module.
Thanks in advance !
First of all you have to override the order template or you can just add handle in the new order template.
Create file vendor/modulename/etc/email_templates.xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Email:etc/email_templates.xsd">
<template id="sales_email_order_template" label="New Order" file="order_new.html" type="html" module="Vendor_ModuleName" area="frontend"/>
<template id="sales_email_order_guest_template" label="New Order for Guest" file="order_new_guest.html" type="html" module="Vendor_ModuleName" area="frontend"/>
</config>
Add handler in the email template file or you can edit email template from magento edit directly and add the below content in the email
{{layout handle="sales_order_info_links" order=$order area="frontend"}}
now create a layout handler vendor/modulename/view/frontend/layout/sales_order_info_links.xml
add below content
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd" label="Email information" design_abstraction="custom">
<body>
<block class="Vendor\ModuleName\Block\Email\Info" name="moduleApickuppointemail" template="email/info.phtml" cacheable="false"/>
</body>
</page>
create block file Vendor/ModuleName/Block/Email/info.php
<?php
namespace Vendor\ModuleName\Block\Email;
use Magento\Sales\Block\Items\AbstractItems;
class Info extends AbstractItems
{
public function __construct(\Magento\Framework\View\Element\Template\Context $context)
{
parent::__construct($context);
}
public function sayHello()
{
return __('Hello World');
}
}
now create phtml file Vendor/ModuleName/view/frontend/templates/email/info.phtml
add Below content
<?php
// incase order data required
$order = $this->getOrder();
/**
* #var \Vendor\ModuleName\Block\Email\Info $block
*/
echo $block->sayHello();
I have my controller in the folder controllers with the name AdController
and my action name is
/**
* action ajaxValue
*
* #param string $argument
* #return void
*/
public function ajaxValueAction($argument = NULL) {
}
and my template file is on location Resources/Private/Templates/Ad/ajaxValue.html
with the name ajaxValue.html
{namespace t=Helhum\TyposcriptRendering\ViewHelpers}
<f:layout name="Default" />
This Template is responsible for creating a table of domain objects.
If you modify this template, do not forget to change the overwrite settings
in /Configuration/ExtensionBuilder/settings.yaml:
Resources:
Private:
Templates:
List.html: keep
Otherwise your changes will be overwritten the next time you save the extension in the extension builder
<f:section name="main">
<f:debug title="Results of customers query">{ads}</f:debug>
<f:flashMessages />
<!-- Category selection box -->
<!-- This is basically called a ajax request which is based on some other file take from the following link http://ajax.helmut-hummel.de/
-->
<div id="dataJson" data-url="{t:uri.ajaxAction(action: 'ajaxValue', format: 'json', controller: 'Ad', pluginName: 'Txcasmarketing') -> f:format.htmlentities()}"></div>
<div class="container">
<div class="btn-group">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">Select Category<span class="caret"></span></a>
<ul class="dropdown-menu">
<f:for each="{categories}" as="category">
<li>
<a data-catUid="{category.uid}" href="#">{category.name}</a>
</li>
</f:for>
</ul>
</div>
</div>
I am getting the following error
<p><strong>Sorry, the requested view was not found.</strong></p> <p>The technical reason is: <em>No template was found. View could not be resolved for action "ajaxValue" in class "CASmarketing\Casmarketing\Controller\AdController"</em>.</p>
The defaults templates which has been created by extension builder is accessible. the structure of my ex_localconf.php is
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'CASmarketing.Casmarketing',
'Txcasmarketing', [
'State' => 'list, show, new, create, edit, update, delete',
'Category' => 'list, show, new, create, edit, update, delete',
'Ad' => 'list, ajaxValue, show, new, create, edit, update, delete'
],
// non-cacheable actions
[
'State' => 'create, update, delete',
'Category' => 'create, update, delete',
'Ad' => 'create, update, delete'
]
);
}, $_EXTKEY
);
and my template file is on location Resources/Templates/Ad/ajaxValue.html
with the name ajaxValue.html
and my step.ts file sitting is
plugin.tx_casmarketing_txcasmarketing {
view {
templateRootPaths.0 = EXT:casmarketing/Resources/Private/Templates/
templateRootPaths.1 = {
$plugin.tx_casmarketing_txcasmarketing.view.templateRootPath}
partialRootPaths.0 = EXT:casmarketing/Resources/Private/Partials/
partialRootPaths.1 = {
$plugin.tx_casmarketing_txcasmarketing.view.partialRootPath}
layoutRootPaths.0 = EXT:casmarketing/Resources/Private/Layouts/
layoutRootPaths.1 = {
$plugin.tx_casmarketing_txcasmarketing.view.layoutRootPath}
}
persistence {
storagePid = {
$plugin.tx_casmarketing_txcasmarketing.persistence.storagePid}
#recursive = 1
}
features {
#skipDefaultArguments = 1
}
mvc {
#callDefaultActionIfActionCantBeResolved = 1
}
}
my script file which is basically called the ajax request which is define in the pageLayout.js
$(".dropdown-menu li a").click(function () {
var jsonUrl = $('#dataJson').attr('data-url')
var selectedCatUid = $(this).attr('data-catUid');
$.ajax({
type: 'POST',
url: jsonUrl,
data: {
'tx_casmarketing_txcasmarketing[catId]': selectedCatUid
},
success: function (response) {
alert(response);
},
});
Your template should not be in Resources/Templates/Ad/ajaxValue.html but in Resources/Private/Templates/Ad/AjaxValue.html. Mind the Private sub folder. Also it has to be UpperCase.
Didn't know that it does matter but the filename usually is uppercase. You also should make sure that the typoscript settings are configured to this directory.
Your typoscript should correctly look like this:
plugin.tx_casmarketing_txcasmarketing {
view {
templateRootPaths.0 = EXT:casmarketing/Resources/Private/Templates/
templateRootPaths.1 = {$plugin.tx_casmarketing_txcasmarketing.view.templateRootPath}
partialRootPaths.0 = EXT:casmarketing/Resources/Private/Partials/
partialRootPaths.1 = {$plugin.tx_casmarketing_txcasmarketing.view.partialRootPath}
layoutRootPaths.0 = EXT:casmarketing/Resources/Private/Layouts/
layoutRootPaths.1 = {$plugin.tx_casmarketing_txcasmarketing.view.layoutRootPath}
}
persistence {
storagePid = {$plugin.tx_casmarketing_txcasmarketing.persistence.storagePid}
#recursive = 1
}
features {
#skipDefaultArguments = 1
}
mvc {
#callDefaultActionIfActionCantBeResolved = 1
}
}
If you change this in your setup.txt of the extension this is hardly cached and you have to clear the cache in the install tool. After making sure your typoscript is correctly loaded place your new Views template inside the ext-directory template path first to try it out.
If this does not help please give us the content of your HTML Template.
how to include Recaptcha service in zend framework 2?
I tried to do like this:
public function contactAction()
{
$formContact = new ContactForm();
$pubKey = 'mypubkey';
$privKey = 'myprivkey';
$recaptcha = new ZendService\ReCaptcha\ReCaptcha($pubKey, $privKey);
return array ('formContact' => $formContact, 'recaptcha' => $recaptcha);
}
but I discovered that ZendService\ReCaptcha is not present by default when you download the framework.
So, I downloaded it from here
https://github.com/zendframework/ZendService_ReCaptcha
and I placed it into vendor\zendframework\zendframework\library\zend together with the other parts of the library.
I tried to refresh the page but doesn't work again because it can't find the zend service recaptcha.
Fatal error: Class 'Application\Controller\ZendService\ReCaptcha\ReCaptcha' not found in C:\Program Files (x86)\xampp\htdocs\Zf-tutorial\module\Application\src\Application\Controller\IndexController.php on line 79
can someone help me? I thought it was simple to implement recaptcha, but it is not so ! thanks!
Add the zendservice-recaptcha module to your composer.json file and run an update:
{
...
"repositories": [
{
"type": "composer",
"url": "http://packages.zendframework.com/"
}
],
...
"require": {
...
"zendframework/zendservice-recaptcha": "*",
...
}
...
}
update composer :
php composer.phar update
This will install the module and configure the relevant class mapping and you will be able to access the classes by adding the use statements as with any other classes you use.
Even i tried recaptcha but with no success so implemented something different to refresh captcha and worked very well, try this once
resetCaptcha function:
$form = $this->getServiceLocator()->get('zfcuser_register_form');
$captcha = $form->get('captcha')->getCaptcha();
$data = array();
$data['id'] = $captcha->generate();
$data['src'] = $captcha->getImgUrl() .
$captcha->getId() .
$captcha->getSuffix();
return $data;
ajax request :
$(document).ready(function() {
$('#refreshcaptcha').click(function() {
var data = [];
var form = <?php $this->registerForm; ?>
data.push({name: "action", value: 'resetCaptcha'});
data.push({name: "params[form]", value: form});
$.post("<?php echo BASE_URL ?>/user/iajax", data,
function(data) {
$('#form_reg img').attr('src', data.src);
$('#captcha-id-hidden').attr('value', data.id);
}, 'json');
});
});
Html call :
<p class="refresh_captcha"><?php echo $this->formCaptcha($form->get('captcha')); ?>
<input type="button" id="refreshcaptcha" value="refresh">
</p>
You do not properly install the library ZendService\ReCaptcha.
your system write:
Class 'Application\Controller\ZendService\ReCaptcha\ReCaptcha' not found
You must:
placed it into vendor\zendframework\zendframework\library
In the file vendor/ZF2/library/Zend/Loader/StandardAutoloader.php insert string
$this->registerNamespace('ZendService', dirname(dirname((__DIR__)))
. '/ZendService');
in case self::AUTOREGISTER_ZF:
in the file init_autoloader.php insert string
$loader->add('ZendService', $zf2Path);.
Environment: JQuery Form Plugin, jQuery 1.7.1, Zend Framework 1.11.11.
Cannot figure out why jQuery won't parse my json object if I specify an url other than a php file.
The form is as follows:
<form id="imageform" enctype="multipart/form-data">
Upload your image <input type="file" name="photoimg" id="photoimg" />
<input type="submit" id ="button" value="Send" />
</form>
The javascript triggering the ajax request is:
<script type="text/javascript" >
$(document).ready(function() {
var options = {
type: "POST",
url: "<?php $this->baseURL();?>/contact/upload",
dataType: 'json',
success: function(result) {
console.log(result);
},
error: function(ob,errStr) {
console.log(ob);
alert('There was an error processing your request. Please try again. '+errStr);
}
};
$("#imageform").ajaxForm(options);
});
</script>
The code in my zend controller is:
class ContactController extends BaseController {
public function init() {
/* Initialize action controller here */
}
public function indexAction() {
}
public function uploadAction() {
if (isset($_POST) and $_SERVER['REQUEST_METHOD'] == "POST") {
$image = $_FILES['photoimg']['tmp_name'];
$im = new imagick($image);
$im->pingImage($image);
$im->readImage($image);
$im->thumbnailImage(75, null);
$im->writeImage('userImages/test/test_thumb.jpg');
$im->destroy();
echo json_encode(array("status" => "success", "message" => "posted successfully"));
}
else
echo json_encode(array("status" => "fail", "message" => "not posted successfully"));
}
}
When I create an upload.php file with the above code, and modify the url from the ajax request to
url: "upload.php",
i don't run into that parsing error, and the json object is properly returned. Any help to figure out what I'm doing wrong would be greatly appreciated! Thanks.
You need either to disable layouts, or using an action helper such as ContextSwitch or AjaxContext (even better).
First option:
$this->_helper->viewRenderer->setNoRender(true);
$this->_helper->layout->disableLayout();
And for the second option, using AjaxContext, you should add in your _init() method:
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('upload', 'json')
->initContext();
This will disable automatically disable layouts and send a json header response.
So, instead of your two json_encode lines, you should write:
$this->status = "success";
$this->message = "posted successfully";
and
$this->status = "fail";
$this->message = "not posted successfully";
In order to set what to send back to the client, you simply have to assign whatever content you want into view variables, and these variables will be automatically convert to json (through Zend_Json).
Also, in order to tell your controller which action should be triggered, you need to add /format/json at the end of your URL in your jQuery script as follow:
url: "<?php $this->baseURL();?>/contact/upload/format/json",
More information about AjaxContext in the manual.
Is the Content-type header being properly set as "application/json" when returning your JSON?
I am implementing a simple ExtJS form that submits to a Struts 2 ActionSupport class. The code for the various components is as follows:
MyAction.java:
//packaging and imports
public class MyAction extends ActionSupport {
private String aField;
private String anotherField;
public String execute() throws Exception {
System.out.println(afield + " " + anotherField); //just checking values, atm
return ActionSupport.SUCCESS;
}
public String getAField() {
return this.aField;
}
public void setAField(String aField) {
this.aField = aField;
}
public String getAnotherField() {
return this.anotherField;
}
public void setAnotherField(String anotherField) {
this.anotherField = anotherField;
}
}
myForm.js:
Ext.onReady(function() {
Ext.QuickTips.init();
// turn on validation errors beside the field globally
Ext.form.Field.prototype.msgTarget = 'side';
var myForm = new Ext.form.FormPanel({
id: 'myFormId',
url: 'submitMyForm.action',
defaults: {
xtype: 'textfield'
},
items: [
{
fieldLabel: 'A Field',
id: 'aField',
name: 'aField',
allowBlank: false
},
{
fieldLabel: 'Another Field',
id: 'anotherField',
name: 'anotherField',
allowBlank: false
}
],
renderTo: 'contentMain'
});
var submitButton = new Ext.Button({
text: 'SUBMIT',
handler: function(button, event) {
myForm.getForm().submit({
url: 'submitMyForm.action',
failure: function() {
Ext.Msg.alert('Error', 'Can not save data.');
}
});
}
});
});
struts.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="myPackage" namespace="/" extends="json-default">
<action name="submitMyForm" class="mycodepackage.MyAction">
<result name="*" type="json">
<param name="includeProperties">aField</param>
</result>
</action>
</package>
</struts>
When the submit button is pressed, my action executes properly, and in addition to standard debugging data prints out:
null null
The JSON result is sent back correctly, but of course is also null:
14:22:17,046DEBUG JSONResult:68 - Adding include property expression: aField
14:22:17,052DEBUG JSONWriter:68 - Ignoring property because of include rule: anotherField
14:22:17,053DEBUG JSONUtil:68 - [JSON]{"aField":null}
Now, it's my understanding that the values entered in the form should be inserted into the instance variables for my action class. Am I wrong in this? If not, what could be going wrong? If so, what can I do to ensure that the form data is sent to my action handler?
Thanks.
Any parameters sent will be placed into the similarly named setters. Why don't you first check that the form parameters are getting sent correctly with LiveHttpHeaders Firefox plugin.
Once we realized the form data was not being correctly passed into the http request, my coworker developed a form data interceptor, which we use to load the data in manually. For more information, look into the <interceptor>, <interceptor-stack>, and <interceptor-ref> tags.