If $post_string
is a string, then no. Changes done to it in the observer class would not be shown in this scope because strings aren't passed by reference to functions.
There are several solutions for that:
Quick but not recommended:
PHP does give you a workaround, by forcing the string to be passed by reference to the function by adding an &
before the the variable name, like so:
Mage::dispatchEvent('my_api_delete_before', array('post_string'=>&$post_string, 'my_cart'=>$this));
But the reason this isn't recommended, as @dedmeet said in his comment:
using call-time pass-by-reference is not supported since PHP version 5.4.0
Directly from the PHP manual:
Note: There is no reference sign on a function call - only on function
definitions. Function definitions alone are enough to correctly pass
the argument by reference. As of PHP 5.3.0, you will get a warning
saying that "call-time pass-by-reference" is deprecated when you use &
in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was
removed, so using it will raise a fatal error.
So here is how to do it in a way that is
Cleaner and recommended:
A better solution would be to create a Varien_Object
because classes are always passed by reference. And any class that extends Varien_Object
and the Varien_Object
itself, gives you the ability to use the getters and setters you find around Mangento.
$obj = new Varien_Object();
// Set a value for data variable
$obj->setFoo($bar);
// The previous function is the same as the following:
// In fact, the previous function will call setData with 'foo' and $bar as its paramteres
$obj->setData('foo', $bar);
// To get the value of 'foo' you will need to call any of the following functions:
$obj->getFoo();
$obj->getData('foo');
So to implement the Varien_object
in the OP's example:
class Foo_Bar_Model_Communicator{
public function someFunction(){
/*
* Assuming that $post_string is getting set here somehow
* before the next line.
*/
$eventData = new Varien_Data();
$eventData->setData('post_string', $post_string);
$eventData->setData('cart', $this);
Mage::dispatchEvent('my_api_delete_before', array('event_data'=>$eventData));
/* In this case, since we sent a Varien_Object as parameter,
* whatever the Observer class does to the object, will be reflected
* here as well.
* We only need to make sure that we get the string back from the
* Varien_Object instead of using $post_string.
*/
$new_post_string = $eventData->getData('post_string');
$result = $this->doApiCommunication($new_post_string);
/*
* We can do the same for the parameters for the next event, but it
* wasn't part of the OP's question and it won't be needed since
* there is no code following the dispatch event.
*
* However it would be a better idea to make the "before" & "after"
* events have the same type of parameters which would be less
* confusing later on.
*/
Mage::dispatchEvent('my_api_delete_after', array('post_string'=>$post_string, 'result'=>$result, 'product'=>$product, 'cart_item_id'=>$_item->cartItemId));
}
}
Taking a quick look at the Magento API files; shows that it goes through a different logic code base at some places, but still trigger events like the example below, inside Mage_Checkout_Model_Cart_Api :
public function createOrder($quoteId, $store = null, $agreements = null)
{
$requiredAgreements = Mage::helper('checkout')->getRequiredAgreementIds();
if (!empty($requiredAgreements)) {
$diff = array_diff($agreements, $requiredAgreements);
if (!empty($diff)) {
$this->_fault('required_agreements_are_not_all');
}
}
$quote = $this->_getQuote($quoteId, $store);
if ($quote->getIsMultiShipping()) {
$this->_fault('invalid_checkout_type');
}
if ($quote->getCheckoutMethod() == Mage_Checkout_Model_Api_Resource_Customer::MODE_GUEST
&& !Mage::helper('checkout')->isAllowedGuestCheckout($quote, $quote->getStoreId())) {
$this->_fault('guest_checkout_is_not_enabled');
}
/** @var $customerResource Mage_Checkout_Model_Api_Resource_Customer */
$customerResource = Mage::getModel("checkout/api_resource_customer");
$isNewCustomer = $customerResource->prepareCustomerForQuote($quote);
try {
$quote->collectTotals();
/** @var $service Mage_Sales_Model_Service_Quote */
$service = Mage::getModel('sales/service_quote', $quote);
$service->submitAll();
if ($isNewCustomer) {
try {
$customerResource->involveNewCustomer($quote);
} catch (Exception $e) {
Mage::logException($e);
}
}
$order = $service->getOrder();
if ($order) {
Mage::dispatchEvent(
'checkout_type_onepage_save_order_after',
array('order' => $order, 'quote' => $quote));
try {
$order->sendNewOrderEmail();
} catch (Exception $e) {
Mage::logException($e);
}
}
Mage::dispatchEvent(
'checkout_submit_all_after',
array('order' => $order, 'quote' => $quote)
);
} catch (Mage_Core_Exception $e) {
$this->_fault('create_order_fault', $e->getMessage());
}
return $order->getIncrementId();
}
Best Answer
You're not going to find a good, clear, deterministic answer here. By and large, you should dispatch events in your module where you and your users need them -- if you can't think of anywhere they might be needed, you don't need to dispatch them. Magento itself emits so many events at so many different places (controller pre/post dispatch, any crud operation, etc) that your module will already dispatch a number of useful events without you doing anything.
Since that's unsatisfying, you'd want your module to dispatch an event when there's some action your module takes that your users might want to add items to, delete items from, change, or take a separate action independent of the original action. For example -- Magento has a
visitor_init
event that's not part of its standard suite of auto generated events. This event allows programmers to modify the visitor objet before Magento logs data. These was no way the original module developers to deterministically know this was where an event needed to be added -- it likely came from feature requests and/or interviews with system users. Know what your users want, and if its not possible/practical to build out a UI/UX to let them do it via the admin, add an event hook so another programmer can do it for them.Less sexily, adding events can also be a cheap way to enable developers (either your users, or even your team) to add some functionality into a gnarly bit of code that everyone's afraid to touch. Plop your
dispatchEvent
call in the middle of the code, hook into it, and you can add your functionality without disturbing the code in the original scope. [Editor: Also you should refactor that awful code at some point]Performance wise, adding an event to dispatch will depend on where you add it. When you call
dispatch
event, Magento needs to make a few extra PHP calls, query the configuration for any configured observers, and then call the observers. Done once, this is a cheap addition in the scope of a standard Magento dispatch. However, done repeatedly, (say, before every block render) this may add up. There's no good rule of thumb here -- as always the right answer is profile.Finally, w/r/t Magento 2, it's still too early to say. All of the above still applies -- however the plugin system adds a few wrinkles. Plugins are, from one point of view, a way to create event like behavior for any public method call in Magento. In theory, if you're designing your classes correctly, you shouldn't ever need an event. However, in practice, dropping an event into a bit of protected or private method code will be a tempting solution for Magento developers when the alternative is a long refactoring process. Also, creating a specifically named event can often create a friendlier experience for developers using your module.
Hope that helps!