Public feed
#889487
<?php
/**
* Habari UserGroup Class
* @package Habari
**/
class UserGroup extends QueryRecord
{
/**
* Static storage for this group's info
* these first three hold the original values as fetched from the DB
* These are associative arrays where the key and value are the same.
* This allows us to use isset() for various checks, rather than
* in_array(), and it allows us to avoid some array iterations
**/
private $db_member_ids= null;
private $db_permissions_granted= null;
private $db_permissons_denied= null;
// these next three hold changes before they're committed to the DB
private $member_ids= null;
private $permissions_granted= null;
private $permissons_denied= null;
private $permissions_revoked= null;
private $toggle_permissions= null;
/**
* get default fields for this record
* @return array an array of the fields used in the UserGroup table
**/
public static function default_fields()
{
return array(
'id' => '',
'name' => ''
);
}
/**
* Constructor for the UserGroup class
* @param array $paramarray an associative array of UserGroup fields
**/
public function __construct( $paramarray= array() )
{
$this->fields= array_merge(
self::default_fields(),
$this->fields );
parent::__construct( $paramarray );
$this->exclude_fields('id');
// set up default, empty properties
$this->permissions_revoked= array();
$this->db_member_ids= array();
$this->db_permissions_granted= array();
$this->db_permissions_denied= array();
$this->toggle_permission['grant']= array();
$this->toggle_permissions['deny']= array();
// if we have an ID, load this UserGroup's members & permissions
if ( $this->id ) {
if ( $result= DB::get_column( 'SELECT user_id FROM {users_groups} WHERE group_id= ?', array( $this->id ) ) ) {
foreach( $result as $id ) {
$this->db_member_ids[ $id ]= $id;
}
}
if ( $result= DB::get_column( 'SELECT permission_id FROM {groups_permissions} WHERE group_id=? AND denied=0 ', array( $this->id ) ) ) {
foreach ( $result as $granted ) {
$this->db_permissions_granted[ $granted ]= $granted;
}
}
if ( $result= DB::get_column( 'SELECT permission_id FROM {groups_permissions} WHERE group_id=? AND denied=1', array( $this->id ) ) ) {
foreach( $result as $denied ) {
$this->permissions_denied[ $denied ]= $denied;
}
}
}
// set the temporary variables to hold the initial values
// as pulled from the DB, if any
$this->member_ids= $this->db_member_ids;
$this->permissions_granted= $this->db_permissions_granted;
$this->permissions_denied= $this->db_permissions_denied;
}
/**
* Create a new UserGroup object and save it to the database
* @param array An associative array of UserGroup fields
* @return UserGroup the UserGroup that was created
**/
public static function create( $paramarray )
{
$usergroup= new UserGroup( $paramarray );
if ( $usergroup->insert() ) {
return $usergroup;
} else {
return $false;
}
}
/**
* Save a new UserGroup to the UserGroup table
**/
public function insert()
{
$allow= true;
// plugins have the opportunity to prevent insertion
$allow= Plugins::filter('usergroup_insert_allow', $allow, $this);
if ( ! $allow ) {
return false;
}
Plugins::act('usergroup_insert_before', $this);
$this->exclude_fields('id');
$result= parent::insertRecord( DB::table('users') );
$this->fields['id']= DB::last_insert_id();
EventLog::log('New group created: ' . $this->name, 'info', 'default', 'habari');
Plugins::act('usergroup_insert_after', $this);
return $result;
}
/**
* Updates an existing UserGroup in the DB
**/
public function update()
{
$allow= true;
// plugins have the opportunity to prevent modification
$allow= Plugins::filter('usergroup_update_allow', $allow, $this);
if ( ! $allow ) {
return false;
}
Plugins::act('usergroup_update_before', $this);
`
// figure out what needs to be changed
// we do this by comparing the various temporary arrays against
// the arrays that hold the DB values
if ( $this->member_ids != $this->db_member_ids ) {
$added= array_diff_assoc( $this->member_ids, $this->db_member_ids);
if ( count( $added ) > 0 ) {
// one or more members added to this group
foreach ( $added as $id ) {
DB::query('INSERT INTO {users_groups} (user_id, group_id) VALUES (?, ?)', array( $id, $this->id) );
}
}
$removed= array_diff_assoc( $this->db_member_ids, $this->member_ids );
if ( count( $removed ) > 0 ) {
// one or more members removed from this group
foreach ( $removed as $id ) {
DB::query('DELETE FROM {users_groups} WHERE user_id=? AND group_id=?', array( $id, $this->id ) );
}
}
}
// were any permissions toggled? We do this to economize hits
// to the DB: rather than execute separate DELETE then INSERT
// commands, we can execute a single UPDATE
if ( ! empty( $this->toggle_permissions['grant'] ) ) {
// grant permissions previously denied
$ids= implode( ',', $this->toggle_permissions['grant'];
$results= DB::query( "UPDATE {groups_permissions} set denied=0 WHERE id IN ($ids)" );
//update DB arrays, to prevent the next set of checks
// from trying to insert this permission
foreach ( $this->toggle_permissions['grant'] as $id ) {
$this->db_permissions_granted[ $id ]= $id;
if ( isset( $this->db_permissions_denied[$id] ) ) {
// this should make the db array match
// its corresponding temp array
unset( $this->db_permissions_denied[$id] );
}
}
}
if ( ! empty( $this->toggle_permissions['deny'] ) ) {
$ids= implode( ',', $this->toggle_permissions['deny'];
$results= DB::query( "UPDATE {groups_permissions} set denied=1 WHERE id IN ($ids)" );
//update DB arrays again
foreach ( $this->toggle_permissions['deny'] as $id ) {
$this->db_permissions_denied[ $id ]= $id;
if ( isset( $this->db_permissions_granted[$id] ) ) {
// this should make the db array match
// its corresponding temp array
unset( $this->db_permissions_granted[$id] );
}
}
}
// now, we compare the current list of granted permissions with
// those currently in the DB. If any new ones have been added,
// update the DB to reflect this
if ( $this->permissions_granted != $this->db_permissions_granted ) {
$granted= array_diff_assoc( $this->permissions_granted, $this->db_permissions_granted );
if ( count( $granted ) > 0 ) {
// one or more permissions granted
foreach( $granted as $perm ) {
DB::query('INSERT INTO {groups_permissions} (group_id, permission_id, denied ) VALUES (?, ?, 0)', array( $this->id, $perm) );
}
}
}
// and do the same for the denied permissions
if ( $this->permissions_denied != $this->db_permissions_denied ) {
$denied= array_diff_assoc( $this->permissions_denied, $this->db_permissions_denied );
if ( count( $denied ) > 0 ) {
// one or more permissions denied
foreach( $denied as $perm ) {
DB::query('INSERT INTO {groups_permissions} (group_id, permission_id, denied) VAlUED (?, ? 1)', array( $this->id, $perm ) );
}
}
}
// finally, were any previously assigned permissions
// (granted or denied) removed? If so, take them out of the DB
if ( count( $this->permissions_revoked ) > 0 ) {
// one or more permissions revoked
foreach ( $this->permissions_revoked as $perm ) {
DB::query( 'DELETE FROM {users_groups} WHERE group_id=? AND permission_id=?', array( $this->id, $perm ) );
}
}
Plugins::act('usergroup_update_after', $this);
// *whew* We're all done!
}
/**
* Delete a UserGroup
**/
public function delete()
{
$allow= true;
// plugins have the opportunity to prevent deletion
$allow= Plugins::filter('usergroup_delete_allow', $allow, $this);
if ( ! $allow ) {
return;
}
Plugins::act('usergroup_delete_before', $this);
// remove all this group's permissions
$results= DB::query( 'DELETE FROM {groups_permissions} WHERE group_id=?', array( $this->id ) );
// remove all this group's members
$results= DB::query( 'DELETE FROM {users_groups} WHERE group_id=?', array( $this->id ) );
// remove this group
$result= parent::deleteRecord( DB::table('groups'), array( 'id' => $this->id ) );
Plugins::act('usergroup_delete_after', $this);
return $result;
}
/**
* function members
* returns an array of user IDs belogning to this UserGroup
* @return array an array of user IDs
**/
public function members()
{
return $this->member_ids;
}
/**
* Add a user to this group
* @param mixed a user ID or name
**/
public function add( $id )
{
if ( ! is_int( $id ) ) {
$user= User::get( $id );
$id= $user->id;
}
if ( isset( $self->member_ids[ $id ] ) ) {
// this user is already a member
return false;
}
$self->member_ids[$id]= $id;
return true;
}
/**
* Remove a user from this group
* @param mixed a user ID or name
**/
public function remove( $id )
{
if ( ! is_int( $id ) ) {
$user= User::get( $id );
$id= $user->id;
}
if ( ! isset( $self->member_ids[ $id ] ) ) {
// this user is not a member of this group
return false;
}
unset($self->member_ids[ $id ]);
return true;
}
/**
* Assign a new permission to this group
* @param int A permission ID
**/
public function grant( $permission )
{
// is this permisson currently assigned to this group?
if ( isset( $this->permissions_granted[ $permission ] ) ) {
// we can short-circuit and stop processing
reutrn true;
}
// is this permission currently denied to ths group?
if ( isset( $permission, $this->permissions_denied[ $permission ] ) ) {
// we need to toggle the denied bit, which is a single
// UPDATE operation, rather than a DELETE + INSERT
$this->toggle_permissions['grant']= $permission;
// we also need to update the temporary variable
// so that the can() method works as expected
// even before calls to update() occur
unset( $this->permissions_denied[ $permission ] );
}
// finally, we grant this permission
$this->permissions_granted[ $permission ]= $permission;
}
/**
* Deny a permission to this group
* @param int The permission ID to be denied
**/
public function deny( $permission )
{
// short-circuit: is this permission already denied?
if ( isset( $this->permissions_denied[ $permission ] ) ) {
return true;
}
// is this permission currently granted?
if ( isset( $this->permissions_granted[ $permission] ) ) {
// we need to toggle the denied bit, which is a single
// UPDATE operation, rather than a DELETE + INSERT
$this->toggle_permissions['deny']= $permission;
// we also need to update the temporary variable
// so that the can() method works as expected
// even before calls to update() occur
unset( $this->permissions_granted[ $permission ] );
}
// finally, we deny the permission
$this->permissions_denied[ $permission ] = $permission;
}
/**
* Remove a permission from a group
* @param int a permission ID
**/
public function revoke( $permission )
{
if ( isset( $this->permissons_granted[ $permission ] ) ) {
unset( $this->permissions_granted[ $permission ] );
}
if ( isset( $permission, $this->permissions_denied[ $permission ] ) ) {
unset( $this->permissions_denied[ $permission] );
}
$this->permissions_revoked[ $permission ]= $permission;
}
/**
* Determine whether members of a group can do something
* @param string a text description of a permission
* @return mixed If a permission is denied to this group, return boolean FALSE; if a permission is granted, return boolean TRUE; if a permission is neither granted nor denied, return an empty string.
**/
public function can( $permission )
{
if ( isset( $this->permissions_denied[ $permission ] ) ) {
return false;
}
if ( isset( $this->permissions_granted[ $permission ] ) ) {
return true;
}
return '';
}
/**
* Fetch a group from the database by ID or name.
* This is a wrapper for get_by_id() and get_by_name()
* @param mixed $group A group ID or name
* @return mixed UserGroup object, or boolean FALSE
*/
public static function get( $group )
{
if ( is_int( $group ) ) {
return self::get_by_id( $group );
} else {
return self::get_by_name( $group );
}
}
/**
* Select a group from the DB by its ID
* @param int A group ID
* @return mixed A UserGroup object, or boolean FALSE
**/
public static function get_by_id( $id )
{
if ( 0 == $id ) {
return false;
}
return DB::get_row( 'SELECT * FROM {groups} WHERE id=?', array( $id ), 'UserGroup' );
}
/**
* Select a group from the DB by its name
* @param string A group name
* @return mixed A UserGroup object, or boolean FALSE
**/
public static function get_by_name( $name )
{
if ( '' == $name ) {
return false;
}
return DB::get_row( 'SELECT * FROM {groups} WHERE name=?', array( $name ), 'UserGroup' );
}
/**
* Determine whether a group exists
* @param mixed The name or ID of the group
* @return bool Whether the group exists or not
**/
public static function exists( $group )
{
if ( is_int( $group ) ) {
$query= 'id';
} else {
$query= 'name';
}
return DB::query("SELECT id FROM {groups} WHERE $query=?", array( $group ) );
}
}
?>