PHP Controller - 4 (creating php hooks)

So what’s a PHP hook?



A PHP hook is a way for an addon or controller to “register” the hook in the system. Once a hook is registered, if it is encountered in the execution of the code, the addon’s private function will be called with a set of parameters.



So you might find things in code that look like:


fn_set_hook('get_product_data', $product_id, $field_list, $join, $auth, $lang_code);




This is from the function fn_get_product_data in the file core/fn.catalog.php. At the point where the fn_set_hook() is called, your addon has the opportunity to act on the parameters passed and or to modify them.



The first arugment is the name of the hook. In your addon’s func.php file, you would add a function named:


fn_movie_get_product_data($product_id, &$fields, &$join, &$auth, $lang_code) {
// empty for now
}




This creates a function that does nothing for now. We will add to it later.



Then in your file init.php, you would add a line of:


fn_register_hooks('get_product_data');




The system will then associate the function name in your addon with this hook and when fn_set_hook() is called, your addon’s “hook” will be executed in the order of it’s priority.



Note that fn_register_hooks() can take multiple arguments. It can also take an array() rather than a string as any argument. If called like:


fn_register_hooks(array('get_product_data', 200));


then the hook will have a priority of 200. This is important in some cases to ensure thar your changes are done at the point you want them to be done.



If you register a hook but there is no associated function within the addon, then a fatal error will occur stating that the hook is not executable. Check your spelling and for other typos.



Since we’re going to use several hooks, our fn_register_hooks() in init.php will look like:


// Standard security trap that should be in all PHP files on the system other than index.php, admin.php, config.php, config.local.php and init.php
if ( !defined('AREA') ) { die('Access denied'); }

fn_register_hooks(
'update_product',
'delete_product',
'get_product_data',
'get_products'
);




Also note that in fn_movie_get_product_data() that the ‘field_list’ and ‘join’ parameters are passed by reference so we can modify them in our hook.



So basically, this hook is going to build on the data that is returned (or looked up in the db) for the get_product_data() function call which is what’s most commonly used to drive the product data for a product detail page and also used in the admin panel for editing viewing a product’s details. The ‘update_product’ hook is used if any of those details are changed in the admin panel and Save is clicked…



Our hook function for get_product_data would look like:


// parameters we want to modify back in the caller should be passed by reference.
// Parameters not used in this operation could be dropped like auth and lang_code
function fn_movie_get_product_data($product_id, &$fields, &$join, &$auth, $lang_code) {
// Return the is_movie field from our table and have it be in the 'product' listing as 'is_movie'
$fields .= ', ?:movies.is_movie as is_movie';
// The join will lookup this product_id and return us the associated is_movie value
$join .= db_quote(" LEFT JOIN ?:movie ON ?:movie.product_id = ?i ", $product_id);
// Not really used (I don't think), but a return is always a good thing since it removes ambiguity
return true;
}




We’re going to modify the field_list and join parameters to find our ‘is_movie’ value from the table we created in addon.xml.



Please see the func.php file in movie2.tgz for the complete init.php and func.php files to this point. An archive is located at:

[url]http://www.ez-ms.com/private/movie2.tgz[/url]

You should pay special attention in understanding the fn_movie_get_products() function. But we’ll get to the details of that later.



In the next segment, we will start putting this together as something the merchant can actually see by having a ‘Movies’ section in the Addons tab of the admin product detail page.

Two questions.


  1. What does the “?:” stand for or mean? I can't find any reference to it in PHP unless I just having a bad day and its obvious.


  2. I see your functions are called fn_movie_get_product_data is this the way

    all functions in an add on will be named, is it standard practice to name

    the function in this way? fn_“addonid”_“registered_hook”? I assume this

    is likely the only way it would work just wanna make sure i'm understanding.

It is part of cs-cart's database API. The '?:' adds the define TABLE_PREFIX to the name (normally cscart_). This allows rebranding providers to have database table names that make no reference to cscart. So for the cscart_users table, you would use “?:users” in the query string.



For a full list of all the '?' modifiers yo would have to look in core/fn.database.php.

[quote name='tbirnseth' timestamp='1318797712' post='123812']

It is part of cs-cart's database API. The '?:' adds the define TABLE_PREFIX to the name (normally cscart_). This allows rebranding providers to have database table names that make no reference to cscart. So for the cscart_users table, you would use “?:users” in the query string.



For a full list of all the '?' modifiers yo would have to look in core/fn.database.php.

[/quote]





I am probably a bit late as these series of -excellent- posts are kind of already aged. I am in the process of following up, and I was wondering if there are some “mistakes” or “mistypings”:

1/ In the following line of code in func.php : shouldn't we have “movies” and not “movie” (as the table name created during installation of the addopn (see addon.xml) is named “movies”.

$join .= db_quote(" LEFT JOIN ?:movie ON ?:movie.product_id = ?i ", $product_id);



2/ in the very same line of code, shouldn't we NOT use the “?:”… in the addon.xml file, we are not creating the table with the “cscart” prefix.



Thanks!



stéphane

What if I need to create a function for a core addon function that does not have a hook I can use. Such as render_newsletter in the news and email addon. How would I get access to the body variable used in the render_newsletter function? Is it even possible without a hook?

You would have to create your own hook but then that would defeat the whole purpose as far as upgrading. Either way you will need to modify the core.

That’s what I was afraid of :(

so basically if i understand right…



init.php i put

fn_register_hooks('dispatch');

and in func.php





i can put




fn_myaddon_name_dispatch() {
// EMPTY
}






howver this triggers error…

Assuming you have an active addon installed name 'myaddon_name' then that will work. However, there needs to be someplace in the code that calls fn_set_hook('dispatch').

Hi @tbirnseth what if I want to override a function name get_product_feature_variants, cause I want to modify its query , right now what i do is

on init.php
array(‘get_product_feature_variants’, 200),

on func.php
function fn_product_modification_get_product_feature_variants($params, $items_per_page = 0, $lang_code = CART_LANGUAGE){
and I modified the query here…
}

and I got This page isn’t working, this is my problem thread related to your topic Override Function - #2 by ecomlabs

Please read the following article at php.net:
PHP: What References Do - Manual

In your function fn_product_modification_get_product_feature_variants you need to pass the $condition parameter by reference (&$condition).

1 Like

Thanks @CS-Cart_team

2 Likes