2001-01-11 10:52:33 +01:00
< ? php
2008-03-15 16:00:15 +01:00
/**
* eGroupWare API - Hooks
2008-04-25 20:54:06 +02:00
*
2008-03-15 16:00:15 +01:00
* @ link http :// www . egroupware . org
* @ author Dan Kuykendall < seek3r @ phpgroupware . org >
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
* Copyright ( C ) 2000 , 2001 Dan Kuykendall
* New method hooks and docu are written by < RalfBecker @ outdoor - training . de >
* @ license http :// opensource . org / licenses / lgpl - license . php LGPL - GNU Lesser General Public License
* @ package api
* @ version $Id $
*/
2003-08-28 16:31:11 +02:00
2008-03-15 16:00:15 +01:00
/**
* class which gives ability for applications to set and use hooks to communicate with each other
*
* Hooks need to be declared in the app ' s setup . inc . php file and they have to be registered
2008-04-25 20:54:06 +02:00
* ( copied into the database ) by
* - installing or updating the app via setup or
2008-03-15 16:00:15 +01:00
* - running Admin >> register all hooks
* As the hooks - class can get cached in the session ( session - type PHP_RESTORE ), you also have to log
* out and in again , that your changes take effect .
*
2008-04-25 20:54:06 +02:00
* Hooks can have one of the following formats :
* - static class method hooks are declared as :
* $setup_info [ 'appname' ][ 'hooks' ][ 'location' ] = 'class::method' ;
* - method hooks , which are methods of a class . You can pass parameters to the call and
* they can return values . They get declared in setup . inc . php as :
2008-03-15 16:00:15 +01:00
* $setup_info [ 'appname' ][ 'hooks' ][ 'location' ] = 'app.class.method' ;
* - old type , which are included files . Values can only be passed by global values and they cant return anything .
2008-04-25 20:54:06 +02:00
* Old declaration in setup . inc . php :
2008-03-15 16:00:15 +01:00
* $setup_info [ 'appname' ][ 'hooks' ][] = 'location' ;
*/
class hooks
{
2005-11-13 07:58:38 +01:00
/**
2008-03-15 16:00:15 +01:00
* Reference to the global db object
2005-11-13 07:58:38 +01:00
*
2008-03-15 16:00:15 +01:00
* @ var egw_db
*/
var $db ;
var $table = 'egw_hooks' ;
2010-01-22 00:31:28 +01:00
/**
* Hooks by location and appname
2011-08-11 09:31:47 +02:00
*
2010-01-22 00:31:28 +01:00
* @ var array $location => $app => $file
*/
var $locations ;
2008-03-15 16:00:15 +01:00
/**
* constructor , reads and caches the complete hooks table
2005-11-13 07:58:38 +01:00
*
2009-05-26 19:26:24 +02:00
* @ param egw_db $db = null database class , if null we use $GLOBALS [ 'egw' ] -> db
2005-11-13 07:58:38 +01:00
*/
2009-05-26 13:55:52 +02:00
function __construct ( $db = null )
2008-03-15 16:00:15 +01:00
{
$this -> db = $db ? $db : $GLOBALS [ 'egw' ] -> db ; // this is to allow setup to set the db
2002-01-02 15:33:05 +01:00
2010-01-22 00:31:28 +01:00
// sort hooks by app-order
foreach ( $this -> db -> select ( $this -> table , 'hook_appname,hook_location,hook_filename' , false , __LINE__ , __FILE__ , false , 'ORDER BY app_order' , 'phpgwapi' , 0 , 'JOIN egw_applications ON hook_appname=app_name' ) as $row )
2008-03-15 16:00:15 +01:00
{
2010-01-22 00:31:28 +01:00
$this -> locations [ $row [ 'hook_location' ]][ $row [ 'hook_appname' ]] = $row [ 'hook_filename' ];
2008-03-15 16:00:15 +01:00
}
2010-01-22 00:31:28 +01:00
//_debug_array($this->locations);
2008-03-15 16:00:15 +01:00
}
2008-04-25 20:54:06 +02:00
2009-05-26 19:26:24 +02:00
/**
* php4 constructor
*
* @ param egw_db $db
* @ deprecated use __construct ()
*/
function hooks ( $db = null )
{
self :: __construct ();
}
2008-03-15 16:00:15 +01:00
/**
2010-01-22 00:31:28 +01:00
* Executes all the hooks ( the user has rights to ) for a given location
2011-08-11 09:31:47 +02:00
*
2010-01-22 00:31:28 +01:00
* If no $order given , hooks are executed in the order of the applications !
2008-03-15 16:00:15 +01:00
*
2010-01-22 00:31:28 +01:00
* @ param string | array $args location - name as string or array with keys location and
2008-03-15 16:00:15 +01:00
* further data to be passed to the hook , if its a new method - hook
2010-01-24 02:31:06 +01:00
* @ param string | array $order appname ( s as value ), which should be executes first
2008-03-15 16:00:15 +01:00
* @ param boolean $no_permission_check if True execute all hooks , not only the ones a user has rights to
* $no_permission_check should * ONLY * be used when it * HAS * to be . ( jengo )
* @ return array with results of each hook call ( with appname as key ) and value :
2010-01-22 00:31:28 +01:00
* - False if no hook exists ( should no longer be the case ),
2008-03-15 16:00:15 +01:00
* - True if old hook exists and
* - whatever the new method - hook returns ( can be True or False too ! ) .
*/
2010-01-22 00:31:28 +01:00
function process ( $args , $order = array (), $no_permission_check = False )
2001-05-06 15:40:04 +02:00
{
2010-01-22 00:31:28 +01:00
//echo "<p>".__METHOD__.'('.array2string($args).','.array2string($order).','.array2string($no_permission_check).")</p>\n";
$location = is_array ( $args ) ? $args [ 'location' ] : $args ;
2003-04-28 00:26:04 +02:00
2010-01-22 00:31:28 +01:00
$hooks = $this -> locations [ $location ];
2010-05-03 10:19:32 +02:00
if ( ! isset ( $hooks ) || empty ( $hooks )) return array (); // not a single app implements that hook
2001-01-11 10:52:33 +01:00
2010-01-22 00:31:28 +01:00
$apps = array_keys ( $hooks );
if ( ! $no_permission_check )
2008-03-15 16:00:15 +01:00
{
2010-05-03 10:19:32 +02:00
// on install of a new egroupware both hook-apps and user apps may be empty/not set
2011-08-11 09:31:47 +02:00
$apps = array_intersect (( array ) $apps , array_keys (( array ) $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ]));
2008-03-15 16:00:15 +01:00
}
2010-01-22 00:31:28 +01:00
if ( $order )
2008-03-15 16:00:15 +01:00
{
2010-01-24 02:31:06 +01:00
$apps = array_unique ( array_merge (( array ) $order , $apps ));
2008-03-15 16:00:15 +01:00
}
2010-01-22 00:31:28 +01:00
$results = array ();
2009-05-26 13:55:52 +02:00
foreach (( array ) $apps as $appname )
2008-03-15 16:00:15 +01:00
{
2010-01-22 00:31:28 +01:00
$results [ $appname ] = $this -> single ( $args , $appname , $no_permission_check );
2001-05-06 15:40:04 +02:00
}
2008-03-15 16:00:15 +01:00
return $results ;
}
2002-01-02 15:33:05 +01:00
2008-03-15 16:00:15 +01:00
/**
* executes a single hook of a given location and application
*
2009-10-20 09:11:58 +02:00
* @ param string | array $args location - name as string or array with keys location , appname and
2008-03-15 16:00:15 +01:00
* further data to be passed to the hook , if its a new method - hook
* @ param string $appname name of the app , which ' s hook to execute , if empty the current app is used
* @ param boolean $no_permission_check if True execute all hooks , not only the ones a user has rights to
* $no_permission_check should * ONLY * be used when it * HAS * to be . ( jengo )
* @ param boolean $try_unregisterd If true , try to include old file - hook anyway ( for setup )
* @ return mixed False if no hook exists , True if old hook exists and whatever the new method - hook returns ( can be True or False too ! ) .
*/
function single ( $args , $appname = '' , $no_permission_check = False , $try_unregistered = False )
{
2009-10-20 09:11:58 +02:00
//echo "<p>hooks::single(".array2string($args).",'$appname','$no_permission_check','$try_unregistered')</p>\n";
if ( ! is_array ( $args )) $args = array ( 'location' => $args );
$location = $args [ 'location' ];
2008-03-15 16:00:15 +01:00
if ( ! $appname )
{
$appname = is_array ( $args ) && isset ( $args [ 'appname' ]) ? $args [ 'appname' ] : $GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ];
}
$SEP = filesystem_separator ();
2002-02-10 20:34:11 +01:00
2008-03-15 16:00:15 +01:00
/* First include the ordered apps hook file */
2010-01-22 00:31:28 +01:00
if ( isset ( $this -> locations [ $location ][ $appname ]) || $try_unregistered )
2008-03-15 16:00:15 +01:00
{
2010-01-22 00:31:28 +01:00
$parts = explode ( '.' , $method = $this -> locations [ $location ][ $appname ]);
2008-04-25 20:54:06 +02:00
if ( strpos ( $method , '::' ) !== false || count ( $parts ) == 3 && $parts [ 1 ] != 'inc' && $parts [ 2 ] != 'php' )
{
// new style hook with method string or static method (eg. 'class::method')
2009-11-16 10:42:53 +01:00
try
{
return ExecMethod ( $method , $args );
}
catch ( egw_exception_assertion_failed $e )
{
if ( substr ( $e -> getMessage (), - 19 ) == '.inc.php not found!' )
{
return false ; // fail gracefully if hook class-file does not exists (like the old hooks do, eg. if app got removed)
}
throw $e ;
}
2008-04-25 20:54:06 +02:00
}
2009-10-20 09:11:58 +02:00
// old style hook, with an include file
if ( $try_unregistered && empty ( $method ))
2002-02-10 20:34:11 +01:00
{
2009-10-20 09:11:58 +02:00
$method = 'hook_' . $location . '.inc.php' ;
}
$f = EGW_SERVER_ROOT . $SEP . $appname . $SEP . 'inc' . $SEP . $method ;
if ( file_exists ( $f ) &&
( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $appname ] || (( $no_permission_check || $location == 'config' || $appname == 'phpgwapi' ) && $appname )) )
{
include ( $f );
return True ;
2002-02-10 20:34:11 +01:00
}
}
2009-10-20 09:11:58 +02:00
return False ;
2008-03-15 16:00:15 +01:00
}
2002-02-10 20:34:11 +01:00
2008-03-15 16:00:15 +01:00
/**
* loop through the applications and count the hooks
*
* @ param string $location location - name
* @ return int the number of found hooks
*/
function count ( $location )
{
2010-01-22 00:31:28 +01:00
return count ( $this -> locations [ $location ]);
2008-03-15 16:00:15 +01:00
}
2011-09-15 16:46:56 +02:00
/**
* check if a given hook for an application is registered
*
* @ param string $location location - name
* @ param string $app appname
* @ return int the number of found hooks
*/
function hook_exists ( $location , $app )
{
//error_log(__METHOD__.__LINE__.array2string($this->locations[$location]));
return count ( $this -> locations [ $location ][ $app ]);
}
2013-05-03 17:31:09 +02:00
/**
* check which apps implement a given hook
*
* @ param string $location location - name
* @ return array of apps implementing given hook
*/
function hook_implemented ( $location )
{
//error_log(__METHOD__.__LINE__.array2string($this->locations[$location]));
return isset ( $this -> locations [ $location ]) ? array_keys ( $this -> locations [ $location ]) : array ();
}
2008-03-15 16:00:15 +01:00
/**
* Register and / or de - register an application ' s hooks
*
* First all existing hooks of $appname get deleted in the db and then the given ones get registered .
*
2008-04-25 20:54:06 +02:00
* @ param string $appname Application 'name'
2008-03-15 16:00:15 +01:00
* @ param array $hooks = null hooks to register , eg $setup_info [ $app ][ 'hooks' ] or not used for only deregister the hooks
2010-09-15 22:09:57 +02:00
* @ return boolean | int false on error , true if new hooks are supplied and registed or number of removed hooks
2008-03-15 16:00:15 +01:00
*/
function register_hooks ( $appname , $hooks = null )
{
if ( ! $appname )
2002-01-02 15:33:05 +01:00
{
2008-03-15 16:00:15 +01:00
return False ;
2002-01-02 15:33:05 +01:00
}
2008-03-15 16:00:15 +01:00
$this -> db -> delete ( $this -> table , array ( 'hook_appname' => $appname ), __LINE__ , __FILE__ );
2003-04-28 00:26:04 +02:00
2008-03-15 16:00:15 +01:00
if ( ! is_array ( $hooks ) || ! count ( $hooks )) // only deregister
2003-04-28 00:26:04 +02:00
{
2010-09-15 22:09:57 +02:00
return $this -> db -> affected_rows ();
2008-03-15 16:00:15 +01:00
}
//echo "<p>ADDING hooks for: $appname</p>";
foreach ( $hooks as $key => $hook )
{
if ( ! is_numeric ( $key )) // new method-hook
2003-04-28 00:26:04 +02:00
{
2008-03-15 16:00:15 +01:00
$location = $key ;
$filename = $hook ;
2003-04-28 00:26:04 +02:00
}
2008-03-15 16:00:15 +01:00
else
2003-04-28 00:26:04 +02:00
{
2008-03-15 16:00:15 +01:00
$location = $hook ;
$filename = " hook_ $hook .inc.php " ;
2003-04-28 00:26:04 +02:00
}
2008-03-15 16:00:15 +01:00
$this -> db -> insert ( $this -> table , array (
'hook_filename' => $filename ,
), array (
'hook_appname' => $appname ,
'hook_location' => $location ,
), __LINE__ , __FILE__ );
2011-09-15 18:53:20 +02:00
$this -> locations [ $location ][ $appname ] = $filename ;
2003-04-28 00:26:04 +02:00
}
2008-03-15 16:00:15 +01:00
return True ;
}
2003-04-28 00:26:04 +02:00
2011-09-15 18:53:20 +02:00
/**
* Add or / update a single application hook
*
* setup file of app will be included and the hook required will be added / or updated
*
* @ param string $appname Application 'name'
* @ param string $location is required , the hook itself
* @ return boolean | int false on error , true if new hooks are supplied and registed or number of removed hooks
*/
function register_single_app_hook ( $appname , $location )
{
if ( ! $appname || empty ( $location ))
{
return False ;
}
$SEP = filesystem_separator ();
// now register the rest again
$f = EGW_SERVER_ROOT . $SEP . $appname . $SEP . 'setup' . $SEP . 'setup.inc.php' ;
$setup_info = array ( $appname => array ());
if ( @ file_exists ( $f )) include ( $f );
// some apps have setup_info for more then themselfs (eg. phpgwapi for groupdav)
foreach ( $setup_info as $appname => $data )
{
if ( $data [ 'hooks' ])
{
if ( $hdata [ $appname ])
{
$hdata [ $appname ][ 'hooks' ] = array_merge ( $hdata [ $appname ][ 'hooks' ], $data [ 'hooks' ]);
}
else
{
$hdata [ $appname ][ 'hooks' ] = $data [ 'hooks' ];
}
}
}
//error_log(__METHOD__.__LINE__.array2string($hdata));
foreach (( array ) $hdata as $appname => $data )
{
if ( array_key_exists ( $location , $data [ 'hooks' ])) $method = $data [ 'hooks' ][ $location ];
}
if ( ! empty ( $method ))
{
//echo "<p>ADDING hooks for: $appname</p>";
$this -> db -> insert ( $this -> table , array (
'hook_appname' => $appname ,
'hook_filename' => $method ,
'hook_location' => $location ,
), array (
'hook_appname' => $appname ,
'hook_location' => $location ,
), __LINE__ , __FILE__ );
$this -> locations [ $location ][ $appname ] = $method ;
return True ;
}
return false ;
}
2008-04-25 20:54:06 +02:00
2008-03-15 16:00:15 +01:00
/**
* Register the hooks of all applications ( used by admin )
*/
function register_all_hooks ()
{
2012-04-13 16:33:43 +02:00
// deleting hooks, to get ride of no longer existing apps
$this -> db -> delete ( $this -> table , '1=1' , __LINE__ , __FILE__ );
2008-04-25 20:54:06 +02:00
2012-04-13 16:33:43 +02:00
// now register all apps using just filesystem data
foreach ( scandir ( EGW_SERVER_ROOT ) as $appname )
2010-01-22 00:31:28 +01:00
{
2012-04-13 16:33:43 +02:00
if ( $appname [ 0 ] == '.' || ! is_dir ( EGW_SERVER_ROOT . '/' . $appname )) continue ;
$f = EGW_SERVER_ROOT . '/' . $appname . '/setup/setup.inc.php' ;
2010-01-22 00:31:28 +01:00
$setup_info = array ( $appname => array ());
if ( @ file_exists ( $f )) include ( $f );
2010-10-20 01:30:16 +02:00
// some apps have setup_info for more then themselfs (eg. phpgwapi for groupdav)
2012-07-18 12:34:31 +02:00
$hdata = array ();
2010-10-20 01:30:16 +02:00
foreach ( $setup_info as $appname => $data )
2011-01-12 11:55:03 +01:00
{
2011-08-11 09:31:47 +02:00
if ( $data [ 'hooks' ])
2011-01-12 11:55:03 +01:00
{
2011-08-11 09:31:47 +02:00
if ( $hdata [ $appname ])
2011-01-12 11:55:03 +01:00
{
$hdata [ $appname ][ 'hooks' ] = array_merge ( $hdata [ $appname ][ 'hooks' ], $data [ 'hooks' ]);
}
else
{
$hdata [ $appname ][ 'hooks' ] = $data [ 'hooks' ];
}
}
}
foreach (( array ) $hdata as $appname => $data )
2010-10-20 01:30:16 +02:00
{
if ( $data [ 'hooks' ]) $this -> register_hooks ( $appname , $data [ 'hooks' ]);
}
2003-04-28 00:26:04 +02:00
}
2001-05-06 15:40:04 +02:00
}
2008-03-15 16:00:15 +01:00
}