2002-09-01 20:59:01 +02:00
< ? php
2006-08-26 17:58:26 +02:00
/**
* API - Interapplicaton links BO layer
*
* Links have two ends each pointing to an entry , each entry is a double :
* - app app - name or directory - name of an egw application , eg . 'infolog'
* - id this is the id , eg . an integer or a tupple like '0:INBOX:1234'
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
2008-03-08 22:41:20 +01:00
* @ copyright 2001 - 2008 by RalfBecker @ outdoor - training . de
2006-08-26 17:58:26 +02:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ package api
* @ subpackage link
* @ version $Id $
*/
2002-09-01 20:59:01 +02:00
2006-08-26 17:58:26 +02:00
/**
* generalized linking between entries of eGroupware apps - SO layer
*
* All vars passed to this class get correct escaped to prevent query insertion .
2008-03-08 22:41:20 +01:00
*
* All methods are now static !
2006-08-26 17:58:26 +02:00
*/
class solink
{
2005-04-06 13:05:57 +02:00
/**
2008-03-08 22:41:20 +01:00
* Name of the links table
2006-08-26 17:58:26 +02:00
*/
2008-03-08 22:41:20 +01:00
const TABLE = 'egw_links' ;
2006-08-26 17:58:26 +02:00
/**
2008-03-08 22:41:20 +01:00
* Turns on debug - messages
2006-08-26 17:58:26 +02:00
*/
2008-03-08 22:41:20 +01:00
const DEBUG = false ;
2006-08-26 17:58:26 +02:00
/**
2008-03-08 22:41:20 +01:00
* Reference to the global db - class
2005-04-08 20:50:51 +02:00
*
2008-03-08 22:41:20 +01:00
* @ var egw_db
2006-08-26 17:58:26 +02:00
*/
2008-03-08 22:41:20 +01:00
private static $db ;
2006-08-26 17:58:26 +02:00
/**
2008-03-08 22:41:20 +01:00
* Reference to current user from $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]
2006-08-26 17:58:26 +02:00
*
2008-03-08 22:41:20 +01:00
* @ var int
2005-04-06 13:05:57 +02:00
*/
2008-03-08 22:41:20 +01:00
protected static $user ;
2002-09-01 20:59:01 +02:00
2006-08-26 17:58:26 +02:00
/**
* creats a link between $app1 , $id1 and $app2 , $id2
*
* @ param string $app1 appname of 1. endpoint of the link
* @ param string $id1 id in $app1
* @ param string $app2 appname of 2. endpoint of the link
* @ param string $id2 id in $app2
* @ param string $remark = '' Remark to be saved with the link ( defaults to '' )
* @ param int $owner = 0 Owner of the link ( defaults to user )
* @ return boolean / int False ( for db or param - error ) or link_id for success
*/
2008-03-08 22:41:20 +01:00
static function link ( $app1 , $id1 , $app2 , $id2 , $remark = '' , $owner = 0 , $lastmod = 0 )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
if ( self :: DEBUG )
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
echo " <p>solink.link(' $app1 ', $id1 ,' $app2 ', $id2 ,' $remark ', $owner )</p> \n " ;
2002-09-01 20:59:01 +02:00
}
2006-08-26 17:58:26 +02:00
if ( $app1 == $app2 && $id1 == $id2 ||
$id1 == '' || $id2 == '' || $app1 == '' || $app2 == '' )
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
return False ; // dont link to self or other nosense
}
2008-03-09 22:14:05 +01:00
if ( $link = self :: get_link ( $app1 , $id1 , $app2 , $id2 ))
2006-08-26 17:58:26 +02:00
{
if ( $link [ 'link_remark' ] != $remark )
2002-09-04 01:09:21 +02:00
{
2008-03-09 22:14:05 +01:00
self :: update_remark ( $link [ 'link_id' ], $remark );
2002-09-04 01:09:21 +02:00
}
2006-08-26 17:58:26 +02:00
return $link [ 'link_id' ]; // link alread exist
}
if ( ! $owner )
{
2008-03-08 22:41:20 +01:00
$owner = self :: $user ;
2006-08-26 17:58:26 +02:00
}
2008-03-08 22:41:20 +01:00
return self :: $db -> insert ( self :: TABLE , array (
2006-08-26 17:58:26 +02:00
'link_app1' => $app1 ,
'link_id1' => $id1 ,
'link_app2' => $app2 ,
'link_id2' => $id2 ,
'link_remark' => $remark ,
'link_lastmod' => $lastmod ? $lastmod : time (),
'link_owner' => $owner ,
2008-03-08 22:41:20 +01:00
), False , __LINE__ , __FILE__ ) ? self :: $db -> get_last_insert_id ( self :: TABLE , 'link_id' ) : false ;
2006-08-26 17:58:26 +02:00
}
/**
* update the remark of a link
*
* @ param int $link_id link to update
* @ param string $remark new text for the remark
* @ return boolean true on success , else false
*/
2008-03-08 22:41:20 +01:00
static function update_remark ( $link_id , $remark )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
return self :: $db -> update ( self :: TABLE , array (
2006-08-26 17:58:26 +02:00
'link_remark' => $remark ,
'link_lastmod' => time (),
), array (
'link_id' => $link_id ,
), __LINE__ , __FILE__ );
}
/**
* returns array of links to $app , $id
*
* @ param string $app appname
2008-03-08 22:41:20 +01:00
* @ param string / array $id id ( s ) in $app
2006-08-26 17:58:26 +02:00
* @ param string $only_app if set return only links from $only_app ( eg . only addressbook - entries ) or NOT from if $only_app [ 0 ] == '!'
* @ param string $order defaults to newest links first
2008-03-08 22:41:20 +01:00
* @ return array id => links pairs if $id is an array or just the links ( only_app : ids ) or empty array if no matching links found
2006-08-26 17:58:26 +02:00
*/
2008-03-08 22:41:20 +01:00
static function get_links ( $app , $id , $only_app = '' , $order = 'link_lastmod DESC' )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
if ( self :: DEBUG )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
echo " <p>solink.get_links( $app , " . print_r ( $id , true ) . " , $only_app , $order )</p> \n " ;
}
2008-03-10 22:01:28 +01:00
if (( $not_only = $only_app [ 0 ] == '!' ))
2008-03-08 22:41:20 +01:00
{
$only_app = substr ( $only_app , 1 );
2006-08-26 17:58:26 +02:00
}
$links = array ();
2008-03-08 22:41:20 +01:00
foreach ( self :: $db -> select ( self :: TABLE , '*' , self :: $db -> expression ( self :: TABLE , '(' , array (
2006-08-26 17:58:26 +02:00
'link_app1' => $app ,
'link_id1' => $id ,
), ') OR (' , array (
'link_app2' => $app ,
'link_id2' => $id ,
), ')'
2008-03-08 22:41:20 +01:00
), __LINE__ , __FILE__ , False , $order ? " ORDER BY $order " : '' ) as $row )
2006-08-26 17:58:26 +02:00
{
2008-04-01 17:49:30 +02:00
// check if left side (1) is one of our targets --> add it
2008-03-08 22:41:20 +01:00
if ( $row [ 'link_app1' ] == $app && in_array ( $row [ 'link_id1' ],( array ) $id ))
2002-09-01 20:59:01 +02:00
{
2008-04-01 17:49:30 +02:00
self :: _add2links ( $row , true , $only_app , $not_only , $links );
2002-10-18 00:02:44 +02:00
}
2008-04-01 17:49:30 +02:00
// check if right side (2) is one of our targets --> add it (both can be true for multiple targets!)
if ( $row [ 'link_app2' ] == $app && in_array ( $row [ 'link_id2' ],( array ) $id ))
2002-09-01 20:59:01 +02:00
{
2008-04-01 17:49:30 +02:00
self :: _add2links ( $row , false , $only_app , $not_only , $links );
2002-09-01 20:59:01 +02:00
}
2006-08-26 17:58:26 +02:00
}
2008-03-08 22:41:20 +01:00
return is_array ( $id ) ? $links : ( $links [ $id ] ? $links [ $id ] : array ());
2006-08-26 17:58:26 +02:00
}
2008-04-01 17:49:30 +02:00
private function _add2links ( $row , $left , $only_app , $not_only , array & $links )
{
$linked_app = $left ? $row [ 'link_app2' ] : $row [ 'link_app1' ];
$linked_id = $left ? $row [ 'link_id2' ] : $row [ 'link_id1' ];
$app_id = $left ? $row [ 'link_id1' ] : $row [ 'link_id2' ];
if ( $only_app && $not_only == ( $linked_app == $only_app ) || ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $linked_app ])
{
return ;
}
$links [ $app_id ][ $row [ 'link_id' ]] = $only_app && ! $not_only ? $linked_id : array (
'app' => $linked_app ,
'id' => $linked_id ,
'remark' => $row [ 'link_remark' ],
'owner' => $row [ 'link_owner' ],
'lastmod' => $row [ 'link_lastmod' ],
'link_id' => $row [ 'link_id' ],
);
}
2006-08-26 17:58:26 +02:00
/**
* returns data of a link
*
* @ param ing / string $app_link_id > 0 link_id of link or app - name of link
* @ param string $id = '' id in $app , if no integer link_id given in $app_link_id
* @ param string $app2 = '' appname of 2. endpoint of the link , if no integer link_id given in $app_link_id
* @ param string $id2 = '' id in $app2 , if no integer link_id given in $app_link_id
* @ return array with link - data or False
*/
2008-03-08 22:41:20 +01:00
static function get_link ( $app_link_id , $id = '' , $app2 = '' , $id2 = '' )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
if ( self :: DEBUG )
2006-08-26 17:58:26 +02:00
{
echo " <p>solink.get_link(' $app_link_id ', $id ,' $app2 ',' $id2 ')</p> \n " ;
2002-09-01 20:59:01 +02:00
}
2006-08-26 17:58:26 +02:00
if (( int ) $app_link_id > 0 )
2005-04-12 18:37:04 +02:00
{
2006-08-26 17:58:26 +02:00
$where = array ( 'link_id' => $app_link_id );
2005-04-12 18:37:04 +02:00
}
2006-08-26 17:58:26 +02:00
else
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
if ( $app_link_id == '' || $id == '' || $app2 == '' || $id2 == '' )
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
return False ;
2002-09-01 20:59:01 +02:00
}
2008-03-08 22:41:20 +01:00
$where = self :: $db -> expression ( self :: TABLE , '(' , array (
2006-08-26 17:58:26 +02:00
'link_app1' => $app_link_id ,
'link_id1' => $id ,
'link_app2' => $app2 ,
'link_id2' => $id2 ,
), ') OR (' , array (
'link_app2' => $app_link_id ,
'link_id2' => $id ,
'link_app1' => $app2 ,
'link_id1' => $id2 ,
), ')' );
2002-09-01 20:59:01 +02:00
}
2008-03-08 22:41:20 +01:00
foreach ( self :: $db -> select ( self :: TABLE , '*' , $where , __LINE__ , __FILE__ ) as $row )
2002-10-18 00:02:44 +02:00
{
2008-03-08 22:41:20 +01:00
if ( self :: DEBUG )
2002-10-18 22:20:35 +02:00
{
2008-03-08 22:41:20 +01:00
_debug_array ( $row );
2002-10-18 00:02:44 +02:00
}
2008-03-08 22:41:20 +01:00
return $row ;
2006-08-26 17:58:26 +02:00
}
return False ;
}
/**
* Remove link with $link_id or all links matching given params
*
* @ param $link_id link - id to remove if > 0
* @ param string $app = '' app - name of links to remove
* @ param string $id = '' id in $app or '' remove all links from $app
* @ param int $owner = 0 account_id to delete all links of a given owner , or 0
* @ param string $app2 = '' appname of 2. endpoint of the link
* @ param string $id2 = '' id in $app2
* @ return array with deleted links
*/
2008-03-08 22:41:20 +01:00
static function & unlink ( $link_id , $app = '' , $id = '' , $owner = 0 , $app2 = '' , $id2 = '' )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
if ( self :: DEBUG )
2006-08-26 17:58:26 +02:00
{
echo " <p>solink.unlink( $link_id , $app , $id , $owner , $app2 , $id2 )</p> \n " ;
}
if (( int ) $link_id > 0 )
{
$where = array ( 'link_id' => $link_id );
}
elseif ( $app == '' AND $owner == '' )
{
return 0 ;
}
else
{
if ( $app != '' && $app2 == '' )
2002-10-18 00:02:44 +02:00
{
2006-08-26 17:58:26 +02:00
$check1 = array ( 'link_app1' => $app );
$check2 = array ( 'link_app2' => $app );
if ( $id != '' )
2003-06-14 15:51:53 +02:00
{
2006-08-26 17:58:26 +02:00
$check1 [ 'link_id1' ] = $id ;
$check2 [ 'link_id2' ] = $id ;
2003-06-14 15:51:53 +02:00
}
2008-03-08 22:41:20 +01:00
$where = self :: $db -> expression ( self :: TABLE , '((' , $check1 , ') OR (' , $check2 , '))' );
2006-08-26 17:58:26 +02:00
}
elseif ( $app != '' && $app2 != '' )
{
2008-03-08 22:41:20 +01:00
$where = self :: $db -> expression ( self :: TABLE , '(' , array (
2006-08-26 17:58:26 +02:00
'link_app1' => $app ,
2004-09-19 18:15:53 +02:00
'link_id1' => $id ,
'link_app2' => $app2 ,
'link_id2' => $id2 ,
), ') OR (' , array (
'link_app1' => $app2 ,
'link_id1' => $id2 ,
2006-08-26 17:58:26 +02:00
'link_app2' => $app ,
'link_id2' => $id ,
2004-09-19 18:15:53 +02:00
), ')' );
2002-10-18 00:02:44 +02:00
}
2006-08-26 17:58:26 +02:00
if ( $owner )
2002-10-18 00:02:44 +02:00
{
2006-08-26 17:58:26 +02:00
if ( $app ) $where = array ( $where );
$where [ 'link_owner' ] = $owner ;
2002-10-18 00:02:44 +02:00
}
}
2006-08-26 17:58:26 +02:00
$deleted = array ();
2008-03-08 22:41:20 +01:00
foreach ( self :: $db -> select ( self :: TABLE , '*' , $where , __LINE__ , __FILE__ ) as $row )
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
$deleted [] = $row ;
}
2008-03-08 22:41:20 +01:00
self :: $db -> delete ( self :: TABLE , $where , __LINE__ , __FILE__ );
2002-09-01 20:59:01 +02:00
2006-08-26 17:58:26 +02:00
return $deleted ;
}
2002-09-01 20:59:01 +02:00
2006-08-26 17:58:26 +02:00
/**
* Changes ownership of all links from $owner to $new_owner
*
* This is needed when a user / account gets deleted
* Does NOT change the modification - time
*
* @ param int $owner acount_id of owner to change
* @ param int $new_owner account_id of new owner
* @ return int number of links changed
*/
2008-03-08 22:41:20 +01:00
static function chown ( $owner , $new_owner )
2006-08-26 17:58:26 +02:00
{
if (( int ) $owner <= 0 || ( int ) $new_owner <= 0 )
2002-09-01 20:59:01 +02:00
{
2006-08-26 17:58:26 +02:00
return 0 ;
}
2008-03-08 22:41:20 +01:00
self :: $db -> update ( self :: TABLE , array ( 'owner' => $new_owner ), array ( 'owner' => $owner ), __LINE__ , __FILE__ );
2002-09-01 20:59:01 +02:00
2008-03-08 22:41:20 +01:00
return self :: $db -> affected_rows ();
2006-08-26 17:58:26 +02:00
}
/**
* Get all links from a given app 's entries to an other app' s entries , which both link to the same 3. app and id
*
* Example :
* I search all timesheet ' s linked to a given project and id ( s ), who are also linked to other entries ,
* which link to the same project :
*
* ( $app = 'timesheet' / some id ) <-- a --> ( other app / other id ) <-- b --> ( $t_app = 'projectmanager' / $t_id = $pm_id )
* ^ ^
* +--------------------------- c -----------------------------------------+
*
* bolink :: get_3links ( 'timesheet' , 'projectmanager' , $pm_id ) returns the links ( c ) between the timesheet and the project ,
* plus the other app / id in the keys 'app3' and 'id3'
*
* @ param string $app app the returned links are linked on one side ( atm . this must be link_app1 ! )
* @ param string $target_app app the returned links other side link also to
* @ param string / array $target_id = null id ( s ) the returned links other side link also to
2008-03-13 12:27:48 +01:00
* @ param boolean $just_app_ids = false return array with link_id => app_id pairs , not the full link record
2006-08-26 17:58:26 +02:00
* @ return array with links from entries from $app to $target_app / $target_id plus the other ( b ) link_id / app / id in the keys 'link3' / 'app3' / 'id3'
*/
2008-03-13 12:27:48 +01:00
static function get_3links ( $app , $target_app , $target_id = null , $just_app_ids = false )
2006-08-26 17:58:26 +02:00
{
2008-03-08 22:41:20 +01:00
$table = self :: TABLE ;
2007-09-12 15:17:02 +02:00
$arrayofselects = array (
// retrieve the type of links, where the relation is realized as timesheet->infolog/tracker via infolog->projectmanager to timesheet->projectmanager
2008-03-08 22:41:20 +01:00
array ( 'table' => self :: TABLE ,
2007-09-12 15:17:02 +02:00
'cols' => 'c.*,b.link_app1 AS app3,b.link_id1 AS id3,b.link_id AS link3' ,
2008-03-08 22:41:20 +01:00
'where' => 'a.link_app1=' . self :: $db -> quote ( $app ) . ' AND c.link_app2=' . self :: $db -> quote ( $target_app ) .
( ! $target_id ? '' : self :: $db -> expression ( self :: TABLE , ' AND c.' , array ( 'link_id2' => $target_id ))),
2007-09-12 15:17:02 +02:00
'join' => " a
2008-03-08 22:41:20 +01:00
JOIN $table b ON a . link_id2 = b . link_id1 AND a . link_app2 = b . link_app1
JOIN $table c ON a . link_id1 = c . link_id1 AND a . link_app1 = c . link_app1 AND a . link_id != c . link_id AND c . link_app2 = b . link_app2 AND c . link_id2 = b . link_id2 " ,
2007-09-12 15:17:02 +02:00
),
// retrieve the type of links, where the relation is realized as timesheet->infolog/tracker and projectmanager->timesheet
2008-03-08 22:41:20 +01:00
array ( 'table' => self :: TABLE ,
2007-09-12 15:17:02 +02:00
'cols' => 'b.link_id, b.link_app2 as app1, b.link_id2 as id1, b.link_app1 as app2, b.link_id1 as id2, b.link_remark,b.link_lastmod,b.link_owner,c.link_app1 AS app3,c.link_id1 AS id3,c.link_id AS link3' ,
2008-03-08 22:41:20 +01:00
'where' => 'a.link_app1=' . self :: $db -> quote ( $app ) . ' AND b.link_app1=' . self :: $db -> quote ( $target_app ) .
( ! $target_id ? '' : self :: $db -> expression ( self :: TABLE , ' AND b.' , array ( 'link_id1' => $target_id ))),
2007-09-12 15:17:02 +02:00
'join' => " a
2008-03-08 22:41:20 +01:00
JOIN $table b ON a . link_id1 = b . link_id2 AND a . link_app1 = b . link_app2
JOIN $table c ON a . link_id2 = c . link_id1 AND a . link_app2 = c . link_app1 AND a . link_id != c . link_id AND c . link_app2 = b . link_app1 AND c . link_id2 = b . link_id1 " ,
),
2007-09-12 15:17:02 +02:00
// retrieve the type of links, where the relation is realized as timesheet->projectmanager and infolog->timesheet
2008-03-08 22:41:20 +01:00
array ( 'table' => self :: TABLE ,
2007-09-12 15:17:02 +02:00
'cols' => 'a.*,c.link_app1 AS app3,c.link_id1 AS id3,c.link_id AS link3' ,
2008-03-08 22:41:20 +01:00
'where' => 'a.link_app1=' . self :: $db -> quote ( $app ) . ' AND a.link_app2=' . self :: $db -> quote ( $target_app ) .
( ! $target_id ? '' : self :: $db -> expression ( self :: TABLE , ' AND a.' , array ( 'link_id2' => $target_id ))),
2007-09-12 15:17:02 +02:00
'join' => " a
2008-03-08 22:41:20 +01:00
JOIN $table b ON a . link_id1 = b . link_id2 AND a . link_app1 = b . link_app2
JOIN $table c ON a . link_id2 = c . link_id2 AND a . link_app2 = c . link_app2 AND a . link_id != c . link_id AND c . link_app1 = b . link_app1 AND c . link_id1 = b . link_id1 " ,
),
2007-09-12 15:17:02 +02:00
);
2008-03-08 22:41:20 +01:00
$links = array ();
foreach ( self :: $db -> union ( $arrayofselects , __LINE__ , __FILE__ ) as $row )
{
2008-03-13 12:27:48 +01:00
if ( $just_app_ids )
{
if ( $row [ 'link_app1' ] == $target_app && ( is_null ( $target_id ) || in_array ( $row [ 'link_id1' ],( array ) $target_id )))
{
$links [ $row [ 'link_id' ]] = $row [ 'link_id2' ];
}
else
{
$links [ $row [ 'link_id' ]] = $row [ 'link_id1' ];
}
}
else
{
$links [] = egw_db :: strip_array_keys ( $row , 'link_' );
}
2008-03-08 22:41:20 +01:00
}
2007-09-12 15:17:02 +02:00
return $links ;
2002-09-01 20:59:01 +02:00
}
2008-03-08 22:41:20 +01:00
/**
2008-04-01 17:49:30 +02:00
* Initialise our static vars
2008-03-08 22:41:20 +01:00
*/
static function init_static ( )
{
self :: $db = $GLOBALS [ 'egw' ] -> db ;
self :: $user =& $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
}
2006-08-26 17:58:26 +02:00
}
2008-03-08 22:41:20 +01:00
solink :: init_static ();