Magento order view button for id process - php

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.

Related

Drupal 7: hook_entity_insert($entity, $type)

I'm a noob junior so I apologise in advance if this is a very basic question and if it has been asked a gazillion times before.
I am basically trying to run another function when a user registers. After some googling I came upon: hook_entity_insert($entity, $type) from (https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_entity_insert/7.x) now, even though there are code examples it does not tell me where to put the code, how to get the data that is submitted etc...
Which file do I put the sample code to test. The sample code provided is:
function hook_entity_insert($entity, $type) {
// Insert the new entity into a fictional table of all entities.
$info = entity_get_info($type);
list($id) = entity_extract_ids($type, $entity);
db_insert('example_entity')
->fields(array(
'type' => $type,
'id' => $id,
'created' => REQUEST_TIME,
'updated' => REQUEST_TIME,
))
->execute();
}
First you should understand the hook system in Drupal. For Drupal 7 this page is a good start. It gives you a quick overview and understanding of the concept.
Understanding the hook system for Drupal modules
There is a specific hook that 'fires' after an user is inserted, named hook_user_insert
You don't need to use hook_entity_insert. In your custom module use below hook
when user registers.
function yourModuleName_form_user_register_alter(&$form, &$form_state) {
// Add your own function to the array of validation callbacks
$form['#validate'][] = 'yourModuleName_user_register_validate';
}
Refer
Hook into Drupal registration and validate user info against business logic
If you want to run a function after the user has registered, use hook_user_insert (or, if this needs to be run every time a user is changed, hook_user_presave).
In general: Hooks in drupal are functions that comply with a specific naming scheme. In the places where a hook is executed (i.e., on user registration), Drupal searches for all modules that contain a function where the function name consists of the module's (machine) name, followed by the hook name. For hook user insert, you would need to implement a module (or place your code in a module you already implemented), see documentation here. Supposing your module is called "custom_module", you then implement a function like so:
function custom_module_user_insert(&$edit, $account, $category) {
//Do what you wanted to do here
}
Hope this helps

CodeIgniter how to set autoloaded database dynamically

Using CodeIgniter 3, I autoload my database config, now how do I change the database connected dynamically ? I was thinking like using session to pass the database value, but session cannot be used in the database config file.
I know I can manually load database and change it, but then I have to call and load the database in every controller and I have tons of the controller, therefore I would like to avoid setting the database manually.
There is probably more than one way to do what you want. The solution shown here uses CodeIgniter’s "Hooks" feature. Specifically, it uses the "post_controller_constructor" hook to match the name of a controller with a specific database configuration defined in database.php.
After the hook does its work the application can make calls to the database in the typical CI way using $this->db->. For example...
$query = $this->db->get('mytable');
This solution is based on the assumption that only one database connection is need for any given controller. This means that all methods in that controller (or any models loaded by the controller) use the same connection.
Here's how it is done.
In application/config/config.php
$config['enable_hooks'] = TRUE;
In application/config/hooks.php
$hook['post_controller_constructor'][] = array(
'class' => '',
'function' => 'set_db_connection',
'filename' => 'post_controller_hook.php',
'filepath' => 'hooks'
);
The file post_controller_hook.php is where the work gets done. It uses lists of controller names to determine which database config is to be loaded.
The list ($controller_lists) contains sub-arrays which group controller names by the db configuration needed. A search is done through each sub-array to find the matching controller name. When a controller name is found the key of that sub-array is the db config to be loaded. If no match is found the 'default' config is used.
The $controller_lists array is hard-coded here but it could easily be loaded from a config file instead. A config file might make maintaining the lists easier.
file application/config/post_controller_hook.php
function set_db_connection()
{
$CI = get_instance();
$controller = $CI->router->class;
$loadConfig = 'default'; //if nothing found in lists we're still good
$controller_lists = array(
'config2' => ['profile'],
'config3' => ['discusion', 'home'],
'config4' => ['suppliers', 'customers', 'inventory', 'orders']
);
foreach($controller_lists as $config_name => $list)
{
if(in_array($controller, $list))
{
$loadConfig = $config_name;
break;
}
}
$CI->load->database($loadConfig);
}
The ability to not load a database for controllers that don't need one could be added if that was desirable. But I'm not going there.
As stated earlier, this solution uses the assumption that only one database configuration (connection) is used for any given controller. If certain methods of a controller need to use a different db configuration this solution becomes more complicated.
Adding the method to the search is easy. The first few lines of set_db_connection() would look like this.
function set_db_connection()
{
$CI = get_instance();
$controller = $CI->router->class;
$method = $CI->router->method;
if($method !== 'index')
{
$controller .= '/'.$method; //append method name
}
$loadConfig = 'default'; //if nothing found in lists we're still good
So now $controller will hold either 'controller/method', or just 'controller' if index() is to being called.
Consider a controller called Viewstate with three methods
class Viewstate extends CI_Controller
{
public function index(){
//uses db 'config4'
}
public function report(){
//uses db 'Config2'
}
public function process(){
//uses db 'Config3'
}
}
We have to include each 'viewstate/method' in the sub-arrays like this.
$controller_lists = array(
'config2' => ['profile', 'viewstate/report'],
'config3' => ['disscusion', 'home', 'viewstate/process'],
'config4' => ['viewstate', 'customers', 'inventory', 'orders']
);
//the rest of the function is as shown earlier
Any 'viewstate/method' not in the search lists it will be assigned the 'default' db config. So it's easy to sort the various needs of viewstate.
The problem is that every 'controller/method' in the site must now be included in the search lists. If the Profile controller has ten methods every combination must now be in the config2 sub-array. So if there are lots of controllers and controller/methods this solution is a poor choice. There might be an elegant way around this problem but that's probably a topic for a new question.

phalcon Dynamic Class creation fails with error?

I am trying to create dynimic model class with a model function inside the user model, however for some reason it unable to identify the class location. it gives me an error
Fatal error: Class 'VarEducation' not found
below is the function
public function partner()
{
$view_service=new ViewService();
$partner_vars_check=$view_service->getUserVarPartnerModelCheckMappingArray();
foreach($partner_vars_check as $partner_key=>$partner_var){
$table= str_replace("p_","var_",$partner_key);
$sql = "SELECT * FROM ".$table."
WHERE id='" . $this->{$partner_key} . "'
ORDER BY id DESC";
$partner_obj = new $partner_var();
$this->{$partner_key} = new \Phalcon\Mvc\Model\Resultset\Simple(null, $partner_obj,
$partner_obj->getReadConnection()->query($sql));
}
}
Any idea on what causing this ?
data supplied by the view service is as below
public function getUserVarPartnerModelCheckMappingArray() {
return array(
'p_education' => 'VarEducation',
'p_body' => 'VarBody',
'p_ethnicity' => 'VarEthnicity',
'p_religion' => 'VarReligion',
'p_family' => 'VarFamily',
);
}
Whatever you do, if you have model hidden in any namespace, you have to deliver full namespaces with your mapping array. Lets say, all your models are in namespace of Application\Models, you have to use it this way:
public function getUserVarPartnerModelCheckMappingArray() {
return array(
'p_education' => '\Application\Models\VarEducation',
'p_body' => '\Application\Models\VarBody',
'p_ethnicity' => '\Application\Models\VarEthnicity',
'p_religion' => '\Application\Models\VarReligion',
'p_family' => '\Application\Models\VarFamily',
);
}
Not saying that I would rather switch/case over such a small amount of options and use models directly, instead of building SQL by hand.
Phalcon should load classes correctly even if the class name is a variable. Try isolating the problem down to just:
$myClass='VarEducation';
$partner_obj = new $myClass();
Also try commenting out that particular model from your model list and see if your other models work, perhaps there's an error in finding that particular model but not others. Check your /app/config/loader.php file and make sure you're registering your models directory. Then make sure the file VarEducation.php exists in your models directory as well as your other models. Also make sure that the class name inside the file matches the file name, and you've named the class VarEducation. Also make sure it's not namespaced. Also make sure you didn't forget the leading <?php and that the file doesn't have any errors. If all else fails, you can simply load the class from your loader.php file with something like:
$loader->registerClasses(array(
'VarEducation' => $config->application->modelsDir.'/VarEducation.php'
));
Make sure a simple test for the model works: $x=new VarEducation(); I suggest doing this from your index controller under a test action. If none of this works, comment on this post with your results when trying my suggestions and I'll update my answer.

Extending / overriding extension in Magento

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

Changing the Page Labels in Yii?

I would like to change the the labels of pages in Yii.
I used Zii.widegt.CListView to show the list of items. The default structure of yii pagination is [previous] 1 2 4 5 6 7 [next] required structure is < 1....10 11 12 13 14 ....40 >.
I read "How can I customize the labels for the pager in Yii?" which is helpful, but how can I show the firstPageLabel as page number 1 instead of << and lastPageLabel as 40 instead of >>.
If you can't find a way to pass in the total item count (i.e. 40) to the lastPageLabel override, you will need to override the CLinkPager class to have this work automatically. The $lastPageLabel is static in the current implementation and does not provide access to variables like "itemCount". You can see the code:
$buttons[]=$this->createPageButton($this->lastPageLabel,$pageCount-1,self::CSS_LAST_PAGE,$currentPage>=$pageCount-1,false);
It just echos $this->lastPageLabel, which is static text.
If you make a new pager (called, say, MyLinkPager), use it like so:
$this->widget('zii.widgets.CListView', array(
'dataProvider' => $categoryProjects,
'itemView' => '_itemDetailsView',
'ajaxUpdate' => false,
'pager' => array(
'class' => 'MyLinkPager', // here is your pager
'firstPageLabel' => '<<',
'prevPageLabel' => '<',
'nextPageLabel' => '>',
'lastPageLabel' => '>>',
),
));
You will have to create your own class that derives from CLinkPager. Ultimately, what you want to achieve is to change the line that thaddeusmt mentions, inside CLinkPager::createPageButtons:
$buttons[]=$this->createPageButton($this->lastPageLabel /* the rest doesn't matter */);
to do the equivalent of
$buttons[]=$this->createPageButton($pageCount /* the rest doesn't matter */);
Now obviously the direct way of doing this is by overriding createPageButtons, but that's not a trivial method and if you do override it completely, you risk your pager becoming "out of sync" with code on later versions of Yii. So let's look for alternatives.
Alternatives
(you might want to skip this part if you 're only interested in the solution)
One alternative would be to override the method, have it call the standard implementation and then simply change what you need to change:
protected function createPageButtons() {
$buttons = parent::createPageButtons(); // Yii's implementation
array_pop($buttons); // remove last item, which is the link for the last page
$buttons[]=$this->createPageButton($this->getPageCount() /* the rest unchanged */);
return $buttons;
}
That's better, but it still involves copy/pasting code so your implementation needs to keep that part in sync with future Yii releases. Can we do better than that? It turns out that yes. Here's the method CLinkPager::run:
public function run()
{
$this->registerClientScript();
$buttons=$this->createPageButtons();
if(empty($buttons))
return;
echo $this->header;
echo CHtml::tag('ul',$this->htmlOptions,implode("\n",$buttons));
echo $this->footer;
}
As you see, CLinkPager doesn't really do a lot other than call createPageButtons. So you could override run and dynamically set the value of $this->lastPageLabel before letting Yii's code run, like this:
public function run()
{
$this->lastPageLabel = $this->getPageCount();
parent::run();
}
Well, this is nice. We managed to achieve the goal by overriding just one method and writing two lines of code. As an added bonus, there's nothing in our code that needs to be kept in sync with Yii if the implementation of CLinkPager changes in the future.
On the other hand, all of these solutions introduce an impurity that could be problematic: when someone writes a view that uses our custom pager class, they might not know that we are actually overriding the value of lastPageLabel! Imagine the "why is it not outputting the label I 'm telling it to?" confusion.
A really nice solution
Fortunately, you can have your pie and eat it too by overriding CLinkPager::init like this:
public function init()
{
// "Hijack" the default values for properties that the user did not set.
// This allows the user to still override this if they want to.
if($this->nextPageLabel===null)
$this->nextPageLabel='<';
if($this->prevPageLabel===null)
$this->prevPageLabel='>';
if($this->firstPageLabel===null)
$this->firstPageLabel='1';
if($this->lastPageLabel===null)
$this->lastPageLabel=$this->getPageCount();
// and let Yii do the rest like it always does
parent::init();
}
You can then configure your view to use this pager, and everything will work just fine without any further ado:
'pager' => array('class' => 'CustomLinkPager'),

Categories