SimpleXML (Zend_Config_Xml actually) and foreach : which tag am I iterating? - simplexml

I'm implementing a little event manager in order to use the Observer pattern. To subscribe my observers to my events, I'm using the following xml file :
<?xml version="1.0" encoding="UTF-8"?>
<configData>
<subscriptions>
<subscription>
<eventName>event_name</eventName>
<class>My_Observer_Class</class>
<function>myFunction</function>
</subscription>
<subscription>
<eventName>other_event_name</eventName>
<class>My_Observer_Otherclass</class>
<function>myOtherFunction</function>
</subscription>
</subscriptions>
</configData>
I'm using a foreach to loop on the subscriptions :
foreach($subscriptions->subscription as $subscription) {
/* using $subscription->eventName etc... */
}
And everything is ok, each $subscription item has it's eventName etc...
But here comes my problem :
<?xml version="1.0" encoding="UTF-8"?>
<configData>
<subscriptions>
<subscription>
<eventName>event_name</eventName>
<class>My_Observer_Class</class>
<function>myFunction</function>
</subscription>
</subscriptions>
</configData>
Here I have only one <subscription> node. And my foreach loops on the subscription children !
To solve this problem, I'd like to know how I can check if the xml file contains several <subscription> tags, or just one...
Any help will be appreciated :)
Edit : Is there a way to use xpath with my Zend_Config_Xml object ?

You can use Xpath.
Please try below code, i have tested it with both of sample XML's you provided.
<?php
$subscriptions = simplexml_load_file('test.xml');
$scTag = $subscriptions->xpath("//subscription");
foreach($scTag as $subscription) {
echo $subscription->eventName;
/* using $subscription->eventName etc... */
}
?>
hope this help !

Just to clarify, this is an issue with Zend_Config_XML which is not present in PHP's native SimpleXML.
Given your second example as $xml, I can run the following and get the word 'subscription' as expected:
$configData = simplexml_load_string($xml);
foreach($configData->subscriptions->subscription as $subscription)
{
echo $subscription->getName();
}

Related

Magento 2 append custom attribute to product name

I would like to add 2 custom attributes after the product name EVERYWHERE in the magento 2 shop.
Like "Productname Attribute1 Attribute2"
Is this possible and how? Do i need to modify every page or is there a way to act directly on the product name rendering for the whole system?
thanks
Fot that you have to create extension. Please check my code
Create folder in app/code/Magenest
Create sub folder in app/code/Magenest/Sample
Now create registration.php with following code
<?php
\Magento\Framework\Component\ComponentRegistrar::register(
\Magento\Framework\Component\ComponentRegistrar::MODULE,
'Magenest_Sample',
__DIR__
);
Create etc folder in app/code/Magenest/Sample/
Create module.xml in etc folder with following code
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="Magenest_Sample" setup_version="2.0.0">
</module></config>
Create folder in frontend in app/code/Magenest/Sample/etc/
Create a file di.xml file in app/code/Magenest/Sample/etc/frontend with following code
<?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\Catalog\Model\Product" type="Magenest\Sample\Model\Product"/>
</config>
Now create a Model folder in app/Magenest/Sample/
Create Product.php in Model folder with following code
<?php
namespace Magenest\Sample\Model;
class Product extends \Magento\Catalog\Model\Product
{
public function getName()
{
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
$product = $objectManager->create('Magento\Catalog\Model\Product')->load($this->_getData('entity_id'));
$myattribute = $product->getResource()->getAttribute('putyourcustomattribute')->getFrontend()->getValue($product);
$changeNamebyPreference = $this->_getData('name') . ' '. $myattribute;
return $changeNamebyPreference;
}
}

Magento 2 - Observer on event 'sales_order_place_after' not working

I am working on a magento 2 observer (without success), to execute a cURL request to a system with the orderid after a order is placed.
Currently I just send an email, but that's for testing purpose only
Working on a Plesk server with a fresh Magento 2.3.2 install (no sample data) and added 1 product. So, fresh webshop with 1 product in total.
Currently I have the following code:
/app/code/CompanyName/ModuleName/etc/events.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="sales_order_place_after">
<observer name="companyname__modulename_observer_afterplaceorder" instance="CompanyName\ModuleName\AfterPlaceOrder" />
</event>
<config>
/app/code/CompanyName/ModuleName/AfterPlaceOrder.php
<?php
namespace CompanyName\ModuleName\Observer;
use Magento\Framework\Event\ObserverInterface;
use Psr\Log\LoggerInterface;
class AfterPlaceOrder implements ObserverInterface {
protected $logger;
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function execute(\Magento\Framework\Event\Observer $observer) {
Mage::log("Start execute module");
$headers = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-type: text/html";
$headers[] = "From: Test SYSTEM";
$headers[] = "X-Mailer: PHP/".phpversion();
mail('testemail#companyname.com', 'Test message', "Order placed", implode("\r\n", $headers));
Mage::log("End of email");
}
}
I've also tried other events like:
- checkout_onepage_controller_success_action
- sales_order_place_after
- sales_order_place_before
- sales_order_save_after
Logs don't seem to work, mail doesn't send and tried die() but nothing works.
It's probably that the event is never fired, but I just can't figure out why.
Can you guys see the error?
P.S. What do you use to debug? Is there a better way then logging?
P.S. I'd also like to now if a observer is the best way for this. Any suggestions?
Thx in advance!
Your /app/code/CompanyName/ModuleName/etc/events.xml is missing the observer folder also the close of the config tag. You could use the event:
checkout_onepage_controller_success_action
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
<event name="checkout_onepage_controller_success_action">
<observer name="companyname__modulename_observer_afterplaceorder" instance="CompanyName\ModuleName\Observer\AfterPlaceOrder"/>
</event>
</config>
To get the orderid just use:
$orderId = $observer->getEvent()->getOrderIds();

Magento 2 How to set custom data / option in a quote item?

I would like to add some data into the quote item, not product.
my approach now is
$quoteItems = $this->cart->getItems();
foreach ($quoteItems as $eachQuoteItem) {
$eachQuoteItem->setCustomname('aaaa');
$eachQuoteItem->setIsSuperMode(true);
$eachQuoteItem->save();
};
I can use $eachQuoteItem->getCustomname(); to get back 'aaaa' in the same page, but i can not get the data in other request.
any suggestion?
thanks
The answers provided address the task of converting the quote items to order items. But, it sounds like you're asking how to set the data on the quote item in the first place.
You can do this by:
a) get items from quote using getAllVisibleItems(),
b) call setData('field', val) on each item.
c) set updated items on quote using setItems(items)
d) then, save the quote
It's late but possibly you need to create plugin for such case as suggested here.
You can save custom field value in quote_item table by following below,
Create ModuleName/CompanyName/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\Quote\Model\Quote\Item">
<plugin name="to_save_custom_field_to_quote_item" type="ModuleName\CompanyName\Plugin\ToQuoteItem" />
</type>
</config>
Create ModuleName\CompanyName\Plugin\ToQuoteItem.php
<?php
namespace ModuleName\CompanyName\Plugin;
use Magento\Quote\Model\Quote\Item;
class ToQuoteItem
{
public function afterBeforeSave(Item $subject)
{
$subject->setCustomField("YOUR_VALUE");
}
}

Joomla 3.x onContentAfterSave not triggering

my over all goal is to grab the articles content after they have saved it and send it though my API. It's stated that onContentAfterSave is fired after they save to the database, my database is getting updated, but nothing coming though api.
Im using Joomla! 3.2.3 Stable
Owtest is my api call, it currently has hard coded data in it.
I feel im either extending the wrong class or missing an import. code below.
<?php
// no direct access
defined('_JEXEC') or die;
jimport('joomla.plugin.plugin');
class plgContentHelloworld extends JPlugin
{
public function onContentAfterSave( $context, &$article, $isNew )
{
owTest();
}
}
?>
Xml Code:
<?xml version="1.0" encoding="utf-8"?>
<extension version="2.5" type="plugin" group="content" method="upgrade">
<name>plg_content_helloworld</name>
<author>Keith</author>
<creationDate>March 18th, 2014</creationDate>
<copyright></copyright>
<license>GNU General Public License</license>
<authorEmail></authorEmail>
<version>1.0</version>
<files>
<filename plugin="helloworld">helloworld.php</filename>
<filename>index.html</filename>
</files>
</extension>
file names are helloworld.php and helloworld.xml respectfully.
what solved my problem was passing article by value and not reference

Add a date picker to system.xml on custom module

As stated in the subject, I am trying to add a date field with its date picker in the System > Configuration area for a custom module (thus using etc/system.xml).
I tried to get inspiration from the thread below :
Magento - Add a button to system.xml with method attached to it
but no success.
I'm sure this is a question of creating the right block or method to create a custom html field but I cannot read thru the Magento Matrix :)
I am stuck at the step where I need to code the class (Datefield.php):
<?php
class Namespace_Module_Block_Datefield extends Mage_Adminhtml_Block_System_Config_Form_Field {
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) {
// ----> Am I wrong in calling ..._Abstract? Should I call Varien_Data_Form_Element_Date? I've tried but no success either...
$this->setElement($element);
$html = // ------------------> what to put here? Call a block or some other method?
->setFormat('d-m-Y')
->setLabel($this->__('Choose date'))
->toHtml();
return $html;
}
}
?>
Do you have a trick on how to do that ?
Thanks a lot.
Hervé
EDIT 02/19/2014: added validation
I found what I think is a more elegant way of doing this. Actually, satrun77 methods is ok but we must place a file in Varien/Data/Form/Element/ which can be overwritten if someone else working on the project unluckily uses the same file/class name. Moreover, this method places the file in the module directories which is, I think, better than distributing files all over the directory tree.
In system.xml:
<?xml version="1.0" encoding="UTF-8"?>
<config>
....
<fields>
...
<run translate="label">
<label>Date</label>
<frontend_type>text</frontend_type> <!-- Use text instead of "myDateSelection" -->
<frontend_model>module/adminhtml_system_config_date</frontend_model> <!-- Call a module specific renderer model -->
<sort_order>20</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<validate>required-entry</validate> <!-- Optional -->
<show_in_store>1</show_in_store>
</run>
</fields>
...
</config>
Create a new file :
app/code/[local, community]/Namespace/Module/Block/Adminhtml/System/Config/Date
with the content below:
class Namespace_Module_Block_Adminhtml_System_Config_Date extends Mage_Adminhtml_Block_System_Config_Form_Field
{
protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
{
$date = new Varien_Data_Form_Element_Date;
$format = Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT);
$data = array(
'name' => $element->getName(),
'html_id' => $element->getId(),
'image' => $this->getSkinUrl('images/grid-cal.gif'),
);
$date->setData($data);
$date->setValue($element->getValue(), $format);
$date->setFormat(Mage::app()->getLocale()->getDateFormat(Mage_Core_Model_Locale::FORMAT_TYPE_SHORT));
$date->setClass($element->getFieldConfig()->validate->asArray());
$date->setForm($element->getForm());
return $date->getElementHtml();
}
}
Create class file in app/code/local/Varien/Data/Form/Element/. Make sure the file name is prefixed with something that identify your module (this is just to differentiate your custom code from Magneto core files)
class Varien_Data_Form_Element_MyDateSelection extends Varien_Data_Form_Element_Date
{
public function getElementHtml()
{
// define image url
$this->setImage(Mage::getDesign()->getSkinUrl('images/grid-cal.gif'));
// define date format
$this->setFormat('yyyy-MM-dd');
return parent::getElementHtml();
}
}
Inside your module system.xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
....
<fields>
...
<run translate="label">
<label>Run now</label>
<frontend_type>myDateSelection</frontend_type>
<sort_order>20</sort_order>
<show_in_default>1</show_in_default>
<show_in_website>1</show_in_website>
<show_in_store>1</show_in_store>
</run>
</fields>
...
</config>
Placing custom code inside lib/ folder or app/Mage/Core/ folder is not the best way to create custom code for Magento. These folders are for core code and not custom code.
This approach creates the least amount of code and does not change any of the core files. So, there isn't any harm from having extra file inside the lib/ folder. But you need to remember that you have extra file for your module in the lib/.
Hope this helps

Resources