Can you Create your Own Hook in Drupal? - php

Is it possible to create your own hook in a Drupal module for other Drupal modules to consume? If not, is there a mechanism in Drupal for third party developers to provide hooks? If everything's been a no so far, where in the core are the list of hooks implemented?
As I understand things, Drupal modules work on a event like system called hooks. When you create a new module, you create functions that implement a hook. For example, there's a hook_delete hook. If you implement a function in your module
function mymodule_delete($node)
{
}
this function will be called whenever a node is deleted.
What I want to know is, is there a way or me, as a third party module developer, to create my own hooks. Say, something like hook_alanskickbutthook so that other module developers could subscribe to this hook.
If this is possible, how do you do it? I've looked around the official docs and haven't found much there, and I still get a little dizzy when I start poking around the Drupal source code (I understand recursion, but don't spend enough time thinking about recursive problems). Full solutions are welcome, but I'm happy to just be pointed in the right direction.

Module_invoke_all() is your ticket to creating your own hooks:
see the API:
http://api.drupal.org/api/drupal/includes--module.inc/function/module_invoke_all
and then look at this great writeup:
http://web.archive.org/web/20101227170201/http://himerus.com/blog/himerus/creating-hooks-your-drupal-modules
(edit: was at http://himerus.com/blog/himerus/creating-hooks-your-drupal-modules but this is now gone)
Once you've made your hook, it can be called in another module using:
/**
* Implementation of hook_myhookname()
*/
function THISMODULENAME_myhookname(args){
//do stuff
}

For example, say you wanted to create hook_my_custom_goodness() for others to use. Then just place code like this in your module at the point where you want the hook to happen:
$variables['msg'] = 'foo';
// Make sure at least one module implements our hook.
if (sizeof(module_implements('my_custom_goodness')) > 0) {
// Call modules that implement the hook, and let them change $variables.
$variables = module_invoke_all('my_custom_goodness', $variables);
}
drupal_set_message($variables['msg']); // Will display 'bar' instead.
Now, if anybody wanted to use your hook, then they could do so in their own module like this:
/**
* Implements hook_my_custom_goodness().
*/
function SOME_OTHER_MODULE_my_custom_goodness($variables) {
$variables['msg'] = 'bar';
return $variables;
}
There is a more complete explanation here:
http://tylerfrankenstein.com/code/drupal-create-custom-hook-for-other-modules

You need to implement two hooks 1. hook_token_info() & 2. hook_tokens() in your module file Below i have given code to create my custom token "query-param-all" and used that token in views- Textarea field.....
/**
* Implements hook_token_info().
*/
function mycustom_token_info() {
$type = [
'name' => ('Custom Token'),
'description' => ('Tokens for custom things.'),
];
$node['query-param-all'] = [
'name' => ("Get all URL query string"),
'description' => ('Get all URL query string'),
];
return [
'types' => ['customtoken' => $type],
'tokens' => ['customtoken' => $node],
];
}
/**
* Implements hook_tokens().
*/
function mycustom_tokens($type, $tokens, array $data, array $options, \Drupal\Core\Render\BubbleableMetadata $bubbleable_metadata) {
$replacements = [];
//print '<pre>'; print_r($data);exit;
$current_path = \Drupal::request()->query->all();
$query_param = '';
if( count($current_path) > 0) {
$amper = '';
$query_param = '?';
foreach($current_path as $key => $value){
$query_param .= $amper.$key.'='.$value;
$amper = '&';
}
}
if ($type == 'customtoken') {
foreach ($tokens as $name => $original) {
switch ($name) {
case 'query-param-all':
$replacements[$original] = $query_param;
break;
}
}
}
return $replacements;
}

If i recall... http://api.drupal.org/api/drupal/modules--node--node.api.php/function/hook_delete/7
does ths help? been a while since I messed with Drupal.
To create/offer custom Drupal hook, you must implement in a ways such that calling the hook with module_invoke or module_invoke_all does not make any conflicts with other module hooks. The name of the hook should be unique and it should offer all/specific feature in such a general way that it doesn't require any type of adjustments with code. All the configuration must go on admin pages and should store those configurations in a separate table or any existing tables create by Drupal or modules on which your modules depends. The hook should be easy to implment by other modules and it should not be much complex to implement. When you create custom hooks, your module(s) act(s) as API provider.

For Drupal 6 & 7, drupal_alter() is probably the best option.
As stated in the module_invoke_all() documentation,
All arguments are passed by value. Use drupal_alter() if you need to
pass arguments by reference.
In Drupal 8, use ModuleHandler::alter.
Passes alterable variables to specific hook_TYPE_alter()
implementations.

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

Implement a search using zend

I have site which is managed using CMS entirely developed on zend. Now I have to Implement a search feature too. I'vent done anything related to search in zend. Some suggestions that I received is to implement a spider. The site will have plenty of links(and it will keep on adding). I'm totally confused and I don't know where to start from. Will zend_search_lucene do the trick?
You probably aren't going to find something completely turnkey for this. If your content is all public, and you are fine with just using a crawler, the easiest thing to implement could be Google Site Search.
http://www.google.com/enterprise/search/products_gss.html
If you need to get different functionality out of the search that this wouldn't offer, you'll likely be stuck doing some code. The Zend Lucene link that Alvar posted is good. One of the ugly things about Zend_Lucene, if I am not mistaken, is that it's relying on the text based lucene indexes without any Java. It's just slower and more cumbersome to manage.
A more robust Lucene based approach is Solr. It's Java based, and runs on it's own service with an API. It scales well, and there's a PHP Pecl out now that will help you communicate with it.
See http://php.net/manual/en/book.solr.php
Another option is Sphinx. This search engine bolts directly to your database, so indexing might be a little more intuitive.
http://sphinxsearch.com/
Good luck to you!
Lucene is strange, i never got it to work properly and developed my own search logic, but maybe this helps:
http://devzone.zend.com/397/roll-your-own-search-engine-with-zend_search_lucene/
Because you are using a home grown product you'll likely be better served by keeping things as simple as possible, at least in the beginning. Also because you're product is home grown you should have a pretty good handle on the data structure.
Building a simple query based search may be something appropriate for starters.
I started with a simple search form:
<?php
class Application_Form_Search extends Zend_Form
{
public function init() {
$this->setMethod('POST');
$this->setDecorators(array(
array('ViewScript', array(
'viewScript' => '_searchForm.phtml'
))
));
// create new element
$query = $this->createElement('text', 'query');
// element options
$query->setLabel('Search Keywords');
$query->setAttribs(array('placeholder' => 'Title',
'size' => 27,
));
// add the element to the form
$this->addElement($query);
$submit = $this->createElement('submit', 'search');
$submit->setLabel('Search Site');
$submit->setDecorators(array('ViewHelper'));
$this->addElement($submit);
}
}
then I built a simple action helper to display and route the form:
<?php
class Library_Controller_Action_Helper_Search extends Zend_Controller_Action_Helper_Abstract
{
public function direct($action, $label = null, $placeHolder = null)
{
$form = new Application_Form_Search();
$form->setAction($action);
$form->search->setLabel($label);
$form->query->setAttribs(array('placeholder' => $placeHolder,
'size' => 27,
));
return $form;
}
}
then I added a placeholder for the search form in my layout.phtml
<?php echo $this->layout()->search ?>
then in the controllers that need to use the search function I add the helper to predispatch():
public function preDispatch()
{
//assign search action helper to view placeholder
$this->_helper->layout()->search = $this->_helper->search(
'url_for_action', 'Submit button label', 'placeholder text'
);
}
then I use a simple mapper method to perform the appropriate query and I usually return a paginator adapter:
public function fetchPagedMoviesByTitle($title)
{
$select = $this->getGateway()->select();
$select->where(new Zend_Db_Expr("title LIKE '%$title%'"));
$select->order('title', 'ASC');
//create a new instance of the paginator adapter and return it
$adapter = new Video_Model_Paginator_Video($select);
return $adapter;
}
This is simple way to implement a search function and is adaptable to most types of queries. I find that a switch statment and a couple of simple database queries and almost any information I need is available.
Good Luck.

How can i create my own hook in drupal6?

How does drupal create its own hook. Similarly i want a customized hook for myself. How am I to proceed ?
May be you are looking for module_invoke_all
Some useful links to start with:
Creating hooks for your Drupal modules
How hooks are invoked with module_invoke_all()
If you have a hook that passes a parameter by reference, and you can not use drupal_alter (for example a presave hook that passes in more than one argument) you can use module_implements.
This way a module could implement it as modulename_foo_presave instead of modulename_presave_alter. It is good for when you you want to let modules alter something at multiple points in its life cycle.
For an example in drupal core checkout the code for the node_validate (drupal 7).
foreach (module_implements('node_validate') as $module) {
$function = $module . '_node_validate';
$function($node, $form, $form_state);
}
from http://api.drupal.org/api/drupal/modules%21node%21node.module/function/node_validate/7
The same approach works in Drupal 6 if you want to create hook that can be implemented in this way.

Where to implement hook_search_info & _execute in order to force a language filter onto search results?

At the moment I am trying to force "current language" onto the list of the options passed into node_search_execute. Unfortunately I'm having trouble finding the right place to put the function hooks. Perhaps I am missing something simple.
I've got myself down to two basic possibilities for how this should be implemented.
(1) Implement hook_search_info and hook_search_execute
In this case, I'd copy the code from node_search_execute and add a line to it that adds "AND Language = '$current_language'" to the search query.
In my theme folder I've tried adding the functions mythemename_search_info and mythemename_search_execute - but they do not execute. When run.
function mythemename_search_info() {
return array(
'title' => 'Content',
'path' => 'node',
'conditions_callback' => 'mythemename_search_execute',
);
}
function mythemename_search_execute($keys = NULL, $conditions = NULL){
return array();
}
In this example - I'd just hope to get "no results" so I could be sure the override was running, then I'd implement the full search functionality.
(2) Implement hook_search_preprocess()
I also tried mythemename_search_preprocess()
function mythemename_search_preprocess($text) {
// Do processing on $text
echo $text; die();
$text = "french";
return $text;
}
But again, I don't get the expected results (a white page with a bit of text on it)
So whatever I'm doing, these search hooks are not getting detected.
What's missing? Do they perhaps have to be in a module?
Yes they do need to be in a module, most hooks are only called for modules and not themes. The most notable exception to this would be theme/preprocess hooks which are called for both.
In case you haven't made one before it's pretty straightforward to create a custom module, there's an invaluable guide here.
I used hook_search_info(), hook_search_execute() and hook_search_access() in my custom module. replaced "hook" with module name. I was able to get the tab created with 'title' of hook_search_info().
and passed he results array in hook_search_execute. with this the results started showing under the tab in search page. So definitely creating a new module will be of help to get a new search tab included.

Observer Pattern Logic Without OOP?

I was thinking about implementing a logic similar to observer pattern on my website, for implementing hooks.
What I am looking for is something similar to this Best way to allow plugins for a PHP application
However the code there is too limited, as I cant attach multiple hooks to same listener.
I am clueless about how to amplify that code to make it able to listen multiple actions at one event.
Thank You
You can do as ircmaxell suggests: add hooks. But clearly, the information he gave was not enough for you.
If you like learning by example, you may look at the CMS Drupal, wich is not OOP, but uses the observer pattern, called hooks all over the place to allow a modular design.
A hook works as follows:
a piece of php looks for the existence of a specially named function.
If that exists, call it and use its output (or do nothing with it)
For example:
Just before an article gets saved in Drupal, the article-system calls the hook_insert
Every module that has a function in the name of ModuleName_insert, will see that function being called. Example: pirate.module may have a function pirate_insert(). The article system makes a roundtrip along all the modules and sees if ModuleName_insert exists. It will pass by pirate module and finds pirate_insert(). It will then call that function (and pass some arguments along too). As such, allowing the pirate.module to change the article just before insertation (or fire some actions, such as turning the body-text into pirate-speek).
The magic happens in so called user_callbacks. An example:
$hook = 'insert'
foreach (module_implements($hook) as $module) {
$function = $module .'_'. $hook;
$result = call_user_func_array($function, $args);
}
And the function module_implements might look something like:
$list = module_list(FALSE, TRUE, $sort); //looks for files that are considered "modules" or "addons".
foreach ($list as $module) {
if (function_exists($module.'_'.$hook)) { //see if the module has the hook 'registered'
$implementations[$hook][] = $module; //if so: add it to a list with functions to be called.
}
}
Simply add a ' * ' hook, and modify the hook() function to call all the 'hooks' in both the named event and the ' * ' event.
Then, simply do:
add_listener('*', 'mycallback');
Take a look at Spl_Observer.
You said you didn't want OOP, but you can easily implement a non-OOP wrapper around this.

Categories