<commit_before><?php
namespace wcf\system\clipboard;
use wcf\data\object\type\ObjectTypeCache;
use wcf\system\cache\CacheHandler;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\SystemException;
use wcf\system\SingletonFactory;
use wcf\system\WCF;
use wcf\util\ClassUtil;

/**
 * Handles clipboard-related actions.
 * 
 * @author	<NAME>
 * @copyright	2001-2011 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package	com.woltlab.wcf
 * @subpackage	system.clipboard
 * @category 	Community Framework
 */
class ClipboardHandler extends SingletonFactory {
	/**
	 * cached list of actions
	 * @var	array
	 */
	protected $actionCache = null;
	
	/**
	 * list of marked items
	 * @var	array<array>
	 */
	protected $markedItems = null;
	
	/**
	 * cached list of page actions
	 * @var	array
	 */
	protected $pageCache = null;
	
	/**
	 * cached list of clipboard item types
	 * @var	array<array>
	 */
	protected $cache = null;
	
	/**
	 * @see	wcf\system\SingletonFactory::init()
	 */
	protected function init() {
		$this->cache = array(
			'objectTypes' => array(),
			'objectTypeNames' => array()
		);
		$cache = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.clipboardItem');
		foreach ($cache as $objectType) {
			$this->cache['objectTypes'][$objectType->objectTypeID] = $objectType;
			$this->cache['objectTypeNames'][$objectType->objectType] = $objectType->objectTypeID;
		}
		
		CacheHandler::getInstance()->addResource(
			'clipboard-page-'.PACKAGE_ID,
			WCF_DIR.'cache/cache.clipboard-page-'.PACKAGE_ID.'.php',
			'wcf\system\cache\builder\ClipboardPageCacheBuilder'
		);
		$this->pageCache = CacheHandler::getInstance()->get('clipboard-page-'.PACKAGE_ID);
	}
	
	/**
	 * Loads action cache.
	 */
	protected function loadActionCache() {
		if ($this->actionCache !== null) return;
		
		CacheHandler::getInstance()->addResource(
			'clipboard-action-'.PACKAGE_ID,
			WCF_DIR.'cache/cache.clipboard-action-'.PACKAGE_ID.'.php',
			'wcf\system\cache\builder\ClipboardActionCacheBuilder'
		);
		$this->actionCache = CacheHandler::getInstance()->get('clipboard-action-'.PACKAGE_ID);
	}
	
	/**
	 * Marks objects as marked.
	 * 
	 * @param	array		$objectIDs
	 * @param	integer		$objectTypeID
	 */
	public function mark(array $objectIDs, $objectTypeID) {
		// remove existing entries first, prevents conflict with INSERT
		$this->unmark($objectIDs, $objectTypeID);
		
		$sql = "INSERT INTO	wcf".WCF_N."_clipboard_item
					(objectTypeID, userID, objectID)
			VALUES		(?, ?, ?)";
		$statement = WCF::getDB()->prepareStatement($sql);
		foreach ($objectIDs as $objectID) {
			$statement->execute(array(
				$objectTypeID,
				WCF::getUser()->userID,
				$objectID
			));
		}
	}
	
	/**
	 * Removes an object marking.
	 * 
	 * @param	array		$objectIDs
	 * @param	integer		$objectTypeID
	 */
	public function unmark(array $objectIDs, $objectTypeID) {
		$conditions = new PreparedStatementConditionBuilder();
		$conditions->add("objectTypeID = ?", array($objectTypeID));
		$conditions->add("objectID IN (?)", array($objectIDs));
		$conditions->add("userID = ?", array(WCF::getUser()->userID));
		
		$sql = "DELETE FROM	wcf".WCF_N."_clipboard_item
			".$conditions;
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute($conditions->getParameters());
	}
	
	/**
	 * Returns a type id by name.
	 * 
	 * @param	string		$typeName
	 * @return	integer
	 */
	public function getObjectTypeID($typeName) {
		if (isset($this->cache['objectTypeNames'][$typeName])) {
			return $this->cache['objectTypeNames'][$typeName];
		}
		
		return null;
	}
	
	/**
	 * Returns a type by type id.
	 * 
	 * @param	integer		$typeID
	 * @return	wcf\data\object\type\ObjectType
	 */
	public function getObjectType($typeID) {
		if (isset($this->cache['objectTypes'][$typeID])) {
			return $this->cache['objectTypes'][$typeID];
		}
		
		return null;
	}
	
	/**
	 * Loads a list of marked items grouped by type name.
	 * 
	 * @param	integer		$typeID
	 */
	protected function loadMarkedItems($typeID = null) {
		$conditions = new PreparedStatementConditionBuilder();
		$conditions->add("userID = ?", array(WCF::getUser()->userID));
		if ($typeID !== null) $conditions->add("typeID = ?", array($typeID));
		
		// fetch object ids
		$sql = "SELECT	objectTypeID, objectID
			FROM	wcf".WCF_N."_clipboard_item
			".$conditions;
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute($conditions->getParameters());
		
		// group object ids by type name
		$data = array();
		while ($row = $statement->fetchArray()) {
			$objectType = $this->getObjectType($row['objectTypeID']);
			if ($objectType === null) {
				continue;
			}
			
			if (!isset($data[$objectType->objectType])) {
				$data[$objectType->objectType] = array(
					'className' => $objectType->listClassName,
					'objectIDs' => array()
				);
			}<commit_msg>Proper error handling for missing list class<commit_after><?php
namespace wcf\system\clipboard;
use wcf\data\object\type\ObjectTypeCache;
use wcf\system\cache\CacheHandler;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\SystemException;
use wcf\system\SingletonFactory;
use wcf\system\WCF;
use wcf\util\ClassUtil;

/**
 * Handles clipboard-related actions.
 * 
 * @author	<NAME>
 * @copyright	2001-2011 WoltLab GmbH
 * @license	GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
 * @package	com.woltlab.wcf
 * @subpackage	system.clipboard
 * @category 	Community Framework
 */
class ClipboardHandler extends SingletonFactory {
	/**
	 * cached list of actions
	 * @var	array
	 */
	protected $actionCache = null;
	
	/**
	 * list of marked items
	 * @var	array<array>
	 */
	protected $markedItems = null;
	
	/**
	 * cached list of page actions
	 * @var	array
	 */
	protected $pageCache = null;
	
	/**
	 * cached list of clipboard item types
	 * @var	array<array>
	 */
	protected $cache = null;
	
	/**
	 * @see	wcf\system\SingletonFactory::init()
	 */
	protected function init() {
		$this->cache = array(
			'objectTypes' => array(),
			'objectTypeNames' => array()
		);
		$cache = ObjectTypeCache::getInstance()->getObjectTypes('com.woltlab.wcf.clipboardItem');
		foreach ($cache as $objectType) {
			$this->cache['objectTypes'][$objectType->objectTypeID] = $objectType;
			$this->cache['objectTypeNames'][$objectType->objectType] = $objectType->objectTypeID;
		}
		
		CacheHandler::getInstance()->addResource(
			'clipboard-page-'.PACKAGE_ID,
			WCF_DIR.'cache/cache.clipboard-page-'.PACKAGE_ID.'.php',
			'wcf\system\cache\builder\ClipboardPageCacheBuilder'
		);
		$this->pageCache = CacheHandler::getInstance()->get('clipboard-page-'.PACKAGE_ID);
	}
	
	/**
	 * Loads action cache.
	 */
	protected function loadActionCache() {
		if ($this->actionCache !== null) return;
		
		CacheHandler::getInstance()->addResource(
			'clipboard-action-'.PACKAGE_ID,
			WCF_DIR.'cache/cache.clipboard-action-'.PACKAGE_ID.'.php',
			'wcf\system\cache\builder\ClipboardActionCacheBuilder'
		);
		$this->actionCache = CacheHandler::getInstance()->get('clipboard-action-'.PACKAGE_ID);
	}
	
	/**
	 * Marks objects as marked.
	 * 
	 * @param	array		$objectIDs
	 * @param	integer		$objectTypeID
	 */
	public function mark(array $objectIDs, $objectTypeID) {
		// remove existing entries first, prevents conflict with INSERT
		$this->unmark($objectIDs, $objectTypeID);
		
		$sql = "INSERT INTO	wcf".WCF_N."_clipboard_item
					(objectTypeID, userID, objectID)
			VALUES		(?, ?, ?)";
		$statement = WCF::getDB()->prepareStatement($sql);
		foreach ($objectIDs as $objectID) {
			$statement->execute(array(
				$objectTypeID,
				WCF::getUser()->userID,
				$objectID
			));
		}
	}
	
	/**
	 * Removes an object marking.
	 * 
	 * @param	array		$objectIDs
	 * @param	integer		$objectTypeID
	 */
	public function unmark(array $objectIDs, $objectTypeID) {
		$conditions = new PreparedStatementConditionBuilder();
		$conditions->add("objectTypeID = ?", array($objectTypeID));
		$conditions->add("objectID IN (?)", array($objectIDs));
		$conditions->add("userID = ?", array(WCF::getUser()->userID));
		
		$sql = "DELETE FROM	wcf".WCF_N."_clipboard_item
			".$conditions;
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute($conditions->getParameters());
	}
	
	/**
	 * Returns a type id by name.
	 * 
	 * @param	string		$typeName
	 * @return	integer
	 */
	public function getObjectTypeID($typeName) {
		if (isset($this->cache['objectTypeNames'][$typeName])) {
			return $this->cache['objectTypeNames'][$typeName];
		}
		
		return null;
	}
	
	/**
	 * Returns a type by type id.
	 * 
	 * @param	integer		$typeID
	 * @return	wcf\data\object\type\ObjectType
	 */
	public function getObjectType($typeID) {
		if (isset($this->cache['objectTypes'][$typeID])) {
			return $this->cache['objectTypes'][$typeID];
		}
		
		return null;
	}
	
	/**
	 * Loads a list of marked items grouped by type name.
	 * 
	 * @param	integer		$typeID
	 */
	protected function loadMarkedItems($typeID = null) {
		$conditions = new PreparedStatementConditionBuilder();
		$conditions->add("userID = ?", array(WCF::getUser()->userID));
		if ($typeID !== null) $conditions->add("typeID = ?", array($typeID));
		
		// fetch object ids
		$sql = "SELECT	objectTypeID, objectID
			FROM	wcf".WCF_N."_clipboard_item
			".$conditions;
		$statement = WCF::getDB()->prepareStatement($sql);
		$statement->execute($conditions->getParameters());
		
		// group object ids by type name
		$data = array();
		while ($row = $statement->fetchArray()) {
			$objectType = $this->getObjectType($row['objectTypeID']);
			if ($objectType === null) {
				continue;
			}
			
			if (!isset($data[$objectType->objectType])) {
				if ($objectType->listclassname == '') {
					throw new SystemException("Missing list class for object type '".$objectType->objectType."'");
				}
				
				$data[$objectType->objectType] = array(
					'className' => $objectType->listclassname,
					'objectIDs' => array()
				);
			}
{'fraction_non_alphanumeric': 0.16221868153754232, 'fraction_numerical': 0.001593308105954989, 'mean_word_length': 4.016483516483516, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 101, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4442789', 'n_tokens_mistral': 3686, 'n_tokens_neox': 3214, 'n_words': 631}