<?php
/**
* PHP versions 5
*
* phTagr : Tag, Browse, and Share Your Photos.
* Copyright 2006-2012, Sebastian Felis (hide@address.com)
*
* Licensed under The GPL-2.0 License
* Redistributions of files must retain the above copyright notice.
*
* @copyright Copyright 2006-2012, Sebastian Felis (hide@address.com)
* @link http://www.phtagr.org phTagr
* @package Phtagr
* @since phTagr 2.2b3
* @license GPL-2.0 (http://www.opensource.org/licenses/GPL-2.0)
*/
class Option extends AppModel {
var $name = 'Option';
var $belongsTo = array('User' => array());
var $_aclMap = array(ACL_LEVEL_GROUP => 'gacl',
ACL_LEVEL_USER => 'uacl',
ACL_LEVEL_OTHER => 'oacl');
function addDefaults($options) {
$ownOptions = Set::extract('/name', $options);
$this->unbindModel(array('belongsTo' => array('User')));
$defaultOptions = $this->findAllByUserId(0);
foreach ($defaultOptions as $default) {
$name = $default[$this->name]['name'];
if (strlen($name) > 2 && substr($name, -2) == '[]') {
$options[] = $default[$this->name];
} else if (!$ownOptions || !in_array($name, $ownOptions)) {
$options[] = $default[$this->name];
}
}
return $options;
}
/**
* Returns the user options as array
*
* @param user User model data
* @return Array of options
*/
function getOptions($user) {
$options = array();
if (!isset($user['Option'])) {
return $options;
}
foreach ($user['Option'] as $o) {
$name = $o['name'];
$value = $o['value'];
if (substr($name, -2) == '[]') {
$name = substr($name, 0, strlen($name) - 2);
if (!isset($options[$name])) {
$options[$name] = array();
}
$options[$name][] = $value;
} else {
$options[$name] = $value;
}
}
return $options;
}
function getTree($userId) {
$this->unbindModel(array('belongsTo' => array('User')));
$data = $this->find('all', array('conditions' => "user_id = $userId OR user_id = 0 ORDER BY user_id ASC"));
return $this->buildTree($data);
}
function buildTree($data, $subPath = null, $strip = false) {
$tree = array();
// Option is set as root
if (isset($data['Option']))
$data = &$data['Option'];
foreach ($data as $item) {
// Option is set as item
if (isset($item['Option'])) {
$option = &$item['Option'];
} else {
$option = &$item;
}
// Skip if subpath does not match
if (isset($subPath) && strpos($option['name'], $subPath) !== 0) {
continue;
} elseif ($strip && strpos($subPath, '.') > 0) {
$option['name'] = substr($option['name'], strrpos($subPath, '.')+1);
}
$node = &$tree;
$paths = explode('.', $option['name']);
for($i=0; $i<count($paths); $i++) {
$path=$paths[$i];
if (strlen($path)>2 && substr($path, -2) == '[]') {
$path = substr($path, 0, strlen($path)-2);
$isArray = true;
} else {
$isArray = false;
}
$node = &$node[$path];
}
if ($isArray) {
$node[] = $option['value'];
} else {
$node = $option['value'];
}
}
return $tree;
}
/**
* Returns the value of a option model data
*
* @param data Model data
* @param name Name of option
* @param default Default value, if value is not found
* @return Value of the option
*/
function _getModelValue($data, $name, $default = null) {
if (!isset($data['Option'])) {
return $default;
}
$isArray = false;
$values = array();
if (strlen($name) > 2 && substr($name, -2) == '[]') {
$isArray = true;
}
foreach ($data['Option'] as $option) {
if ($option['name'] === $name) {
if (!$isArray) {
return $option['value'];
} else {
$values[] = $option['value'];
}
}
}
if ($isArray && count($values)) {
return $values;
}
return $default;
}
/**
* Returns the value of a given path from the data
*
* @param data Option tree data or model data
* @param path Path of the data to extract
* @param default Default value, if the path does not exists
* @return Extracted option (or default value)
* @see _getModelValue
*/
function getValue($data, $path, $default = null) {
if (isset($data['Option'])) {
return $this->_getModelValue($data, $path, $default);
}
$value = Set::extract($data, $path);
if (!empty($value)) {
return $value;
}
return $default;
}
function setValue($name, $value, $userId = null) {
if (strlen($name) > 1 && substr($name, -2) == '[]') {
return $this->addValue($name, $value, $userId);
}
if ($userId !== null) {
$this->data['User']['id'] = $userId;
} else {
$userId = $this->data['User']['id'];
}
$data = $this->find('first', array('conditions' => array('Option.user_id' => $userId, 'Option.name' => $name)));
if ($data) {
$data['Option']['value'] = $value;
$this->save($data);
} else {
$this->create(array('Option' => array('name' => $name, 'value' => $value, 'user_id' => $userId)));
$this->save();
}
}
function addValue($name, $value, $userId = null) {
if (strlen($name) < 2 || substr($name, -2) != '[]') {
return $this->setValue($name, $value, $userId);
}
if ($userId !== null) {
$this->data['User']['id'] = $userId;
} else {
$userId = $this->data['User']['id'];
}
$this->create(array('Option' => array('name' => $name, 'value' => $value, 'user_id' => $userId)));
$this->save();
}
function delValue($name, $value = null, $userId = null) {
if ($userId !== null) {
$this->data['User']['id'] = $userId;
} else {
$userId = $this->data['User']['id'];
}
$conditions = array('user_id' => $userId, 'name' => $name);
if ($value) {
$conditions['value'] = $value;
}
$this->deleteAll(array('AND' => $conditions));
}
/**
* Increase the ACL level. It checks the current flag and increases the ACL
* level of lower ACL levels (first level is ACL_LEVEL_GROUP, second level is
* ACL_LEVEL_USER and the third level is ACL_LEVEL_OTHER).
*
* @param data Array of image data
* @param flag Threshold flag which indicates the upper inclusive bound
* @param mask Bit mask of flag
* @param level Highes ACL level which should be increased
*/
function _increaseAcl(&$data, $flag, $mask, $level) {
//Logger::debug("Increase: {$data['gacl']},{$data['uacl']},{$data['oacl']}: $flag/$mask ($level)");
if ($level>ACL_LEVEL_OTHER)
return;
for ($l=ACL_LEVEL_GROUP; $l<=$level; $l++) {
$name = $this->_aclMap[$l];
if (($data[$name]&($mask))<$flag)
$data[$name]=($data[$name]&(~$mask))|$flag;
}
//Logger::debug("Increase (result): {$data['gacl']},{$data['uacl']},{$data['oacl']}: $flag/$mask ($level)");
}
/**
* Decrease the ACL level. Decreases the ACL level of higher ACL levels
* according to the current flag (first level is ACL_LEVEL_GROUP, second level
* is ACL_LEVEL_USER and the third level is ACL_LEVEL_OTHER). The decreased ACL
* value is the ACL value of the higher levels which is less than the current
* threshold or it is zero if no lower ACL value is available.
*
* @param data Array of image data
* @param flag Threshold flag which indicates the upper exlusive bound
* @param mask Bit mask of flag
* @param level Lower ACL level which should be downgraded
*/
function _decreaseAcl(&$data, $flag, $mask, $level) {
//Logger::debug("Decrease: {$data['gacl']},{$data['uacl']},{$data['oacl']}: $flag/$mask ($level)");
if ($level<ACL_LEVEL_GROUP)
return;
for ($l=ACL_LEVEL_OTHER; $l>=$level; $l--) {
$name = $this->_aclMap[$l];
// Evaluate the available ACL value which is lower than the threshold
if ($l==ACL_LEVEL_OTHER)
$lower = 0;
else {
$next = $this->_aclMap[$l+1];
$lower = $data[$next]&($mask);
}
$lower=($lower<$flag)?$lower:0;
if (($data[$name]&($mask))>=$flag)
$data[$name]=($data[$name]&(~$mask))|$lower;
}
//Logger::debug("Decrease (result): {$data['gacl']},{$data['uacl']},{$data['oacl']}: $flag/$mask ($level)");
}
function setAcl(&$data, $flag, $mask, $level) {
if ($level<ACL_LEVEL_KEEP || $level>ACL_LEVEL_OTHER)
return false;
if ($level==ACL_LEVEL_KEEP)
return $data;
if ($level>=ACL_LEVEL_GROUP)
$this->_increaseAcl(&$data, $flag, $mask, $level);
if ($level<ACL_LEVEL_OTHER)
$this->_decreaseAcl(&$data, $flag, $mask, $level+1);
return $data;
}
function addDefaultAclTree($tree) {
if (!isset($tree['acl']['write']['tag'])) {
$tree['acl']['write']['tag'] = ACL_LEVEL_USER;
}
if (!isset($tree['acl']['write']['meta'])) {
$tree['acl']['write']['meta'] = ACL_LEVEL_GROUP;
}
if (!isset($tree['acl']['read']['preview'])) {
$tree['acl']['read']['preview'] = ACL_LEVEL_OTHER;
}
if (!isset($tree['acl']['read']['original'])) {
$tree['acl']['read']['original'] = ACL_LEVEL_GROUP;
}
if (!isset($tree['acl']['group'])) {
$tree['acl']['group'] = -1;
}
return $tree;
}
function getDefaultAcl($data) {
$tree = $this->buildTree($data);
// default values
$acl = array(
'groupId' => $this->getValue($tree, 'acl.group', -1),
'gacl' => ACL_READ_ORIGINAL | ACL_WRITE_META,
'uacl' => ACL_READ_PREVIEW | ACL_WRITE_TAG,
'oacl' => ACL_READ_PREVIEW
);
$this->setAcl(&$acl, ACL_WRITE_TAG, ACL_WRITE_MASK, $this->getValue($tree, 'acl.write.tag', ACL_LEVEL_OTHER));
$this->setAcl(&$acl, ACL_WRITE_META, ACL_WRITE_MASK, $this->getValue($tree, 'acl.write.meta', ACL_LEVEL_USER));
$this->setAcl(&$acl, ACL_READ_PREVIEW, ACL_READ_MASK, $this->getValue($tree, 'acl.read.preview', ACL_LEVEL_OTHER));
$this->setAcl(&$acl, ACL_READ_ORIGINAL, ACL_READ_MASK, $this->getValue($tree, 'acl.read.original', ACL_LEVEL_GROUP));
return $acl;
}
}
?>