Extending / overriding extension in Magento - php

I have an extension installed and I want to use its funcionality from my modules. The postAction in that extension is where all happens. It uses youtube API to retrieve a video information and save it on several tables on the Magento EAV data model.
Already have a functional module that I created to test youtube API functions using just a button and a text box to send some search term. But now I want to do it automatically using the extension funcionalities to make that call and fill in the necessary tables instead of doing everything manually from my code.
So I need (or want? or must?) to setup a call to that postAction or extend or override it. I'm lost here, I'm new to Magento and PHP so I havenĀ“t a clear idea on what to do.
This is the class I want to call:
/**
* Youtube Upload Controller
*/
class AW_Vidtest_YoutubeController extends Mage_Core_Controller_Front_Action {
.....
}
And inside it the postAction function:
/**
* Get customer video
*/
public function postAction() {
$data = new Varien_Object($this->getRequest()->getPost());
....
}
I have read the information on these links but I'm not clear on what exactly I'm must do. Follow the Observer pattern? Maybe just creating a post call by myself and somehow adding the $data structure so it can be used on the call? Thanks
How do I overwrite/extend an abstract class?
avoiding extension conflicts
block override from two different modules
overriding magento bloc in multiple modules
Edited:
This is the code I have until now, with suggestions made by #Francesco. The function printVideoEntry is called from other function, inside a for each that for now walks the first 3 products on the catalog.
<?php
class Dts_Videotestimonials_Model_SearchVideo extends Mage_Core_Model_Abstract
{
public $search_term;
private $productModel;
function printVideoEntry($videoEntry, $_product, $tabs = "")
{
# get user data
$user = Mage::getSingleton('admin/session');
$userName = $user->getUser()->getFirstname();
$userEmail = $user->getUser()->getEmail();
$data = array(
"ProductId" => $_product->getId(),
"AuthorEmail" => $userEmail,
"AuthorName" => $userName,
"VideoLink" => $videoEntry->getVideoWatchPageUrl(),
"VideoType" => "link",
"Title" => $videoEntry->getVideoTitle(),
"Comment" => "this is a comment"
);
$actionUrl = Mage::getUrl('vidtest/youtube/post');
Mage::app()->getResponse()->setRedirect($actionUrl, $data);
}
}

It is not easy to give a clear answer ... the question is not clear because we don't know how the youtube extension works. ( the code is crypted or open ? )
Call a Controller's Action
If you want to just call postAction you can use _redirect($path, $arguments=array()) method. ( defined in Mage/Core/Controller/Varien/Action.php )
$path is defined as 'moduleName/controllerName'
$arguments=array() are defined as couple parameterName => Value.
Ex.
$this->_redirect('checkout/cart', array('Pname' => $pValue, ... );
This will work only if you call it from a Controller ...
you can find more info about _redirect here: magento _redirect with parameters that have + or /
In case you want to do a redirection from a model or any different file form a Controller one you will need to call the url in this way :
Mage::app()->getResponse()->setRedirect(Mage::getUrl($path, $arguments=array()));
so the above ex. becames:
Mage::app()->getResponse()->setRedirect(Mage::getUrl('checkout/cart', array('Pname' => $pValue, ... ));
Observer
Using an Observer means add a new model to your module ( the observer ) and write inside this class a method that perform an action under certain events, probably you want to calls some model/method of the yt extension.
Then you have to declare this stuff in you config.xml binding you observer method to some event ( any predefined even in Magento that suit you or if you need you should create your own rewriting the magento class ... )
Example for Observer
PackageName/ModuleName/Model/Observer.php
class PackageName_ModuleName_Model_Observer {
public function myActionMethod(Varien_Event_Observer $observer) {
// Code ...
// just a very indicative example
$model = Mage::getModel('youtubeExtension/Model....').method();
}
}
PackageName/ModuleName/etc/config.xml
<config>
....
<global>
<events>
<EventName>
<observers>
<moduleName_observer>
<type>singleton</type>
<class>PackageName_ModuleName_Model_Observer</class>
<method>myActionMethod</method>
</moduleName_observer>
</observers>
</EventName>
</events>
</global>
....
Obviously change EventName and all fake name according to your package/module/methods names
The most of the difficult is to find the right event that suit you ...
Everytime you see in magento code something like Mage::dispatchEvent('EventName', Parameters); this is an event.
you can find a list of default Magento event Here
I hope it helps you

Just try to extends your module class
class AW_Vidtest_YoutubeController extends Mage_Core_Controller_Front_Action {
.....
}
example
class AW1_Vidtest1_YoutubeController1 extends AW_Vidtest_YoutubeController {
.....
}
where
AW1_Vidtest1_YoutubeController1 Aw1 is namespace Vidtest1 is your module name YoutubeController1 is your controller where you want post action to use.
Hope it's work for you

Related

How update object with relation 1:n in a hook in TYPO3

I have an A entity and this have a property call B as relation 1:n from B to A. When I update A in TCA backend interface, when an particular field is active, the solution runs a hook of type function processDatamap_postProcessFieldArray (...)
I have to create a new element of B and save in ObjectStorage attribute of A. This works in execute time, create an objet and attaching it, but can not save in DB. I have tried with functions of extbase and Repository but it does not work. In my reserch identified the framework Doctrine for create queries, similar to persistence behavior, but in this case I could save the new object of B.
My question is: how could I use Doctrine for build query that allows to make update for object A, adding the new element B and save this element in the relation in DB.
I am working with TYPO3 7.6
You shouldn't use Extbase within the DataHandler hooks. Also plain database queries (neither with Dotrine or TYPO3_DB) are not good idea for creating entities within BE. Better way is to use TYPO3 DataHandler API. Example creation of Entity B during create/edit of Entity A could look like that.
Register hook typo3conf/ext/example/ext_localconf.php
defined('TYPO3_MODE') || die('Access denied.');
$GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['t3lib/class.t3lib_tcemain.php']['processDatamapClass']['example'] = 'Vendor\\Example\\DataHandling\\DataHandler';
typo3conf/ext/example/Classes/DataHandling/DataHandler.php
namespace Vendor\Example\DataHandling;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\StringUtility;
class DataHandler implements SingletonInterface
{
public function processDatamap_afterDatabaseOperations(
string $status,
string $table,
$id,
$fieldArray,
\TYPO3\CMS\Core\DataHandling\DataHandler $dataHandler
) {
// Do nothing if other table is processed
if ($table !== 'tx_example_domain_model_entitya') {
return;
}
// Get real UID of entity A if A is new record
$idOfEntityA = $dataHandler->substNEWwithIDs[$id];
// Example fields of entity B
$entityB = [
'sys_language_uid' => '0',
'entitya' => $idOfEntityA,
'hidden' => '0',
'title' => 'I\'m entitty B',
'starttime' => '0',
'endtime' => '0',
'pid' => $fieldArray['pid'],
];
// Add entity B associated with entity A
$dataHandler->start(
[
'tx_example_domain_model_entityb' => [
StringUtility::getUniqueId('NEW') => $entityB
]
],
[]
);
$dataHandler->process_datamap();
}
}
Tested on 8.7, but will work on 7.6 too. Here you can read more about DataHandler https://docs.typo3.org/typo3cms/CoreApiReference/8.7/ApiOverview/Typo3CoreEngine/Database/
In contrary to the previous answer, I see no reason, why extbase shouldn`t be used in the DataHandler Hooks. I do it myself in an extension with dynamic objects that are being synchronized via a SOAP-Webservice.
You got to keep few things in mind (in this order inside the hooked function) :
-Obey naming policies !!
-Instantiate the ObjectManager manually via GeneralUtility::makeInstance
-Get ALL the repositories manually (with all I mean really all.. also repositories of childs of models you are working with inside the hooked function).
-Create new object instances with object manager => not with "new".
Then you can just add childs to parents as you are used to.. but dont forget to persistAll() via persistenceManager manually in the end.
Hope this could help. Basically, a function hooked via DataMap Hook acts like a static function called via ajax => you have to make sure to get all the desired utilities and managing classes manually, because typo3 doesn`t auto-inject them.
Hope this helps,
Oliver

How to run no action and a single variable in the Silverstripe url_handlers?

I'm working on a project which has a special page type which checks a single 250 alphanumeric string.
Ideally I'd like the URL structure to work like this:
http://www.example.com/check/I1gdTVUsnezY9SDI8V0GS2mg7Y0IdG6MqjCZ8t1yejRdi0pKzyr7G28iF0fyxOW9Le9vg3op7NnuCE0unT7d09aN00Trn7xPYAjLRhqQ9k5aRlsThsTk0HaS966MCDb4aC23RW4Cl273e9YiWKFNm2STI75X1jnlZ684M7ejDpmWg1YfM32OpwX066bF5VTp5v0F5I42T2SWh8QhMc9GW9I2ZbuP7ykh710UHnLwQyA3BO7KitZWcCU0u9
However using allowed_actions and url_handlers the standard way I can only get it to work if I preface the alphanumeric string with "uid" - http://www.example.com/check/uid/string-goes-here
class CheckPage_Controller extends Page_Controller {
private static $allowed_actions = array(
'uid'
);
private static $url_handlers = array(
'uid/$uID' => 'uid'
);
Is it possible to have url_handlers work with just a variable and no action on a custom page?
You can define a route without a action in your _config.php:
Director::addRules(100, array(
'check/$UID' => 'CheckPage_Controller'
));
and in your CheckPage_Controller you can catch the request in the index function:
public function index() {
var_dump($this->request->allParams());die;
}
But you should be aware that the add route catches all requests to /check/whatever. So you need to define a different url for other stuff.
Assuming you have a pagetype "CheckPage" with $URLSegment "check" and some Dataobjects in a has_many relation you can use Nightjars extension for using this urlslug method, which is really elegant:
https://github.com/NightJar/silverstripe-slug/
ATM it's no ready to install module but an extension to the controller you can configure.
If you need any further help please provide some more informations about your code structure.

Magento order view button for id process

I must place a button in order view that will send further the order id. The id will be used for a simple database query then it should return to order view.
I found out how to create the button, I created app/code/local/Mage/Adminhtml/Block/Sales/Order/View.php following the view.php from core.
Here is my code :
class Mage_Adminhtml_Block_Sales_Order_View extends
Mage_Adminhtml_Block_Widget_Form_Container
{
public function __construct()
{
$this->_objectId = 'order_id';
$this->_controller = 'sales_order';
$this->_mode = 'view';
parent::__construct();
$this->_removeButton('delete');
$this->_removeButton('reset');
$this->_removeButton('save');
$this->setId('sales_order_view');
$order = $this->getOrder();
$this->_addButton('release_payment', array(
'label' => Mage::helper('sales')->__('Release Payment'),
'onclick' => 'setLocation(\'' . $this->getUrl('*/*/release') . '\')',
'class' => 'go'
));
}
What I want is that this location that should be sales_order/release to actually do something with the order id. I tried to understand how but I can't manage to actually create the controller.
You should probably collect those overrides into a module. The ugly method would otherwise be to copy
app/code/core/Mage/Adminhtml/controllers/OrderController.php
to
app/code/local/Mage/Adminhtml/controllers/OrderController.php
and add the releaseAction()-function to it.
For the more elegant solution you would need to create a module with config options in it's etc/config.xml file to override/overload the specified block and controller code. With this method your changes are better contained and it's easy to switch the module on/off. Also when extending the original block/controller you don't need to include anything other then the modified/added methods, the rest will be executed from the original file.
Actually even the main documentation from Magento has decent examples:
http://www.magentocommerce.com/wiki/5_-_modules_and_development/0_-_module_development_in_magento/how_to_overload_a_controller
And Googling for magento controller overloadgives good results too, so I won't give an lengthy example right here.

Return data back to dispatcher from event observer in Magento

I have an extension for product registration that dispatches an event after the registration is saved. Another extension uses that event to generate a coupon for a virtual product if it is related to the registered product.
I need to get back data on the generated coupon to send to the user in an email along with the details of their product registration.
Is there a way to return data from the observer back to where the event is dispatched?
There is a trick available in Magento for your purpose. Since you can pass event data to the observers, like product or category model, it also possible to create a container from which you can get this data.
For instance such actions can be performed in dispatcher:
$couponContainer = new Varien_Object();
Mage::dispatchEvent('event_name', array('coupon_container' => $couponContainer));
if ($couponContainer->getCode()) {
// If some data was set by observer...
}
And an observer method can look like the following:
public function observerName(Varien_Event_Observer $observer)
{
$couponContainer = $observer->getEvent()->getCouponContainer();
$couponContainer->setCode('some_coupon_code');
}
Enjoy and have fun!
No, there's nothing built in to the system for doing this. The Magento convention is to create a stdClass or Varien_Object transport object.
Take a look at the block event code
#File: app/code/core/Mage/Core/Block/Abstract.php
...
if (self::$_transportObject === null)
{
self::$_transportObject = new Varien_Object;
}
self::$_transportObject->setHtml($html);
Mage::dispatchEvent('core_block_abstract_to_html_after',
array('block' => $this, 'transport' => self::$_transportObject));
$html = self::$_transportObject->getHtml();
...
Since self::$_transportObject is an object, and PHP objects behave in a reference like manner, any changes made to the transport object in an observer will be maintained. So, in the above example, if an observer developer said
$html = $observer->getTransport()-setHtml('<p>New Block HTML');
Back up in the system block code self::$_transportObject would contain the new HTML. Keep in mind that multiple observers will have a chance to change this value, and the order observers fire in Magento will be different for each configured system.
A second approach you could take is to use Magento's registry pattern. Register a variable before the dispatchEvent

Execute PHP script inside Joomla! cms once - geo based redirection

Hi
I'm trying to figure the best way to execute a PHP script inside Joomla!
I want to redirect users if they are not from X country (already have a database and the script)
I found this extension but I want to make my own stuff http://bit.ly/daenzU
1) How could I execute the script once for each visitor? Working with Cookies?
2) As I'll put the script inside Joomla! template, I'll modify templates/XXX/index.php
3) Based on 2), Joomla! loads templates/XXX/index.php each time a page loads, so I have to avoid redirection script to be executed twice for an user
Thanks in advance for your ideas and suggestions
Just remember that, in Joomla 3.x, (according to the docs) in order to check an information about the user before the 'Login' event, you need to create you plugin in the 'authentication' context. That is, you need to have your plugin at 'root_to_joomla/plugins/authentication/myplugin/myplugin.php'.
Also, your plugin should be a class named PlgAuthenticationMyplugin, it shold extend the base plugin class 'JPlugin' and should have a public method named 'onUserAuthenticate'.
<?php
...
class PlgAuthenticationMyplugin extends JPlugin {
...
public function onUserAuthenticate($credentials, $options, &$response)
{
//your code here (check the users location or whatever)
}
....
If you want to do that after the Login event, your plugin should be at the user context, at root_to_joomla/plugins/user/myplugin/myplugin.php. And should have a public method 'onUserLogin'.
<?php
class PlgUserMyplugin extends JPLugin {
...
public function onUserLogin($user, $options)
{
//your test goes here
}
...
You can see all other User related events here.
DO NOT modify the template, this will do the trick but is not the right place.
I advise you to create a plug-in, see Joomla docs on plug-ins. Here is event execution order of events.
Create a system plugin and implement onAfterInitialise method. In that method add all of your code.
To prevent the execution of script twice for each user set the user state, see Joomla documentation for states. You can also use session $session = JFactory::getSession(), see documentation.
Here is code... for your plug-in.
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
jimport( 'joomla.plugin.plugin' );
class plgMyPlugin extends JPlugin {
//
public function __construct(){
// your code here
}
//
public function onAfterInitialise(){
$app = JFactory::getApplication();
//
$state = $app->getUserStateFromRequest( "plgMyPlugin.is_processed", 'is_processed', null );
if (!$state){
// your code here
// ....
// Set the Steate to prevent from execution
$app->setUserState( "plgMyPlugin.is_processed", 1 );
}
}
}

Categories