<commit_before><?php

class Tiki_Profile_Installer
{
	private $installed = array();
	private $handlers = array(
		'tracker' => 'Tiki_Profile_InstallHandler_Tracker',
		'tracker_field' => 'Tiki_Profile_InstallHandler_TrackerField',
		'tracker_item' => 'Tiki_Profile_InstallHandler_TrackerItem',
		'wiki_page' => 'Tiki_Profile_InstallHandler_WikiPage',
		'category' => 'Tiki_Profile_InstallHandler_Category',
		'file_gallery' => 'Tiki_Profile_InstallHandler_FileGallery',
		'module' => 'Tiki_Profile_InstallHandler_Module',
		'menu' => 'Tiki_Profile_InstallHandler_Menu',
		'blog' => 'Tiki_Profile_InstallHandler_Blog',
		'blog_post' => 'Tiki_Profile_InstallHandler_BlogPost',
		'plugin_alias' => 'Tiki_Profile_InstallHandler_PluginAlias',
		'webservice' => 'Tiki_Profile_InstallHandler_Webservice',
		'webservice_template' => 'Tiki_Profile_InstallHandler_WebserviceTemplate',
		'rss' => 'Tiki_Profile_InstallHandler_Rss',
		'topic' => 'Tiki_Profile_InstallHandler_Topic',
		'article_type' => 'Tiki_Profile_InstallHandler_ArticleType',
		'article' => 'Tiki_Profile_InstallHandler_Article',
		'forum' => 'Tiki_Profile_InstallHandler_Forum',
		'template' => 'Tiki_Profile_InstallHandler_Template',
		'perspective' => 'Tiki_Profile_InstallHandler_Perspective',
		'users' => 'Tiki_Profile_UsersHandler',
	);

	private static $typeMap = array(
		'wiki_page' => 'wiki page',
		'file_gallery' => 'fgal',
	);

	private $userData = false;
	
	private $feedback = array();	// Let users know what's happened

	/**
	 * @param $feed - (strings append, array replaces) lines of feedback text
	 * @return none
	 */
	function setFeedback( $feed ) {
		if (is_array( $feed )) {
			$this->feedback = $feed;
		} else {
			$this->feedback[] = $feed;
		}
	}
	
	/**
	 * @param $index - (int) index of feedback string to return if present
	 * @return string or whole array if no index specified 
	 */
	function getFeedback( $index ) {
		if (isset( $index ) && $index < count($this->feedback) ) {
			return $this->feedback[ $index ];
		} else {
			return $this->feedback;
		}
	}
	
	public static function convertType( $type ) // {{{
	{
		if( array_key_exists( $type, self::$typeMap ) )
			return self::$typeMap[$type];
		else
			return $type;
	} // }}}

	public static function convertObject( $type, $id ) // {{{
	{
		global $tikilib;

		if( $type == 'wiki page' && is_numeric( $id ) )
			return $tikilib->get_page_name_from_id( $id );
		else
			return $id;
	} // }}}

	function __construct() // {{{
	{
		global $tikilib;

		$result = $tikilib->query( "SELECT DISTINCT domain, profile FROM tiki_profile_symbols" );
		if ( $result ) while( $row = $result->fetchRow() )
			$this->installed[Tiki_Profile::getProfileKeyFor( $row['domain'], $row['profile'] )] = true;
	} // }}}

	function setUserData( $userData ) // {{{
	{
		$this->userData = $userData;
	} // }}}

	function getInstallOrder( Tiki_Profile $profile ) // {{{
	{
		// Obtain the list of all required profiles
		$dependencies = $profile->getRequiredProfiles(true);
		$dependencies[$profile->getProfileKey()] = $profile;

		$referenced = array();
		$knownObjects = array();
		foreach( Tiki_Profile_Object::getNamedObjects() as $o )
			$knownObjects[] = Tiki_Profile_Object::serializeNamedObject( $o );

		// Build the list of dependencies for each profile
		$short = array();
		foreach( $dependencies as $key => $profile )
		{
			$short[$key] = array();
			foreach( $profile->getRequiredProfiles() as $k => $p )
				$short[$key][] = $k;

			foreach( $profile->getNamedObjects() as $o )
				$knownObjects[] = Tiki_Profile_Object::serializeNamedObject( $o );
			foreach( $profile->getReferences() as $o )
				$referenced[] = Tiki_Profile_Object::serializeNamedObject( $o );

			if( ! $this->isInstallable( $profile ) )
				return false;
		}

		// Make sure all referenced objects actually exist
		$remain = array_diff( $referenced, $knownObjects );
		if( ! empty( $remain ) )
			throw new Exception( "Unknown objects are referenced: " . implode( ', ', $remain ) );

		// Build the list of packages that need to be installed
		$toSequence = array();
		foreach( $dependencies as $key => $profile )
			if( ! $this->isInstalled( $profile ) )
				$toSequence[] = $key;

		// Order the packages to make sure all dependencies are met
		$toInstall = array();
		$counter = 0;
		while( count( $toSequence ) )
		{
			// If all packages were tested and no order was found, exit
			// Probably means there is a circular dependency
			if( $counter++ > count( $toSequence ) * 2 )
				throw new Exception( "Profiles could not be ordered: " . implode( ", ", $toSequence ) );

			$key = reset( $toSequence );

			// Remove packages that are already scheduled or installed from dependencies
			$short[$key] = array_diff( $short[$key], array_keys( $this->installed ), $toInstall );

			$element = array_shift( $toSequence );
			if( count( $short[$key] ) )
				$toSequence[] = $element;
			else
			{
				$counter = 0;
				$toInstall[] = $element;
			}
		}

		$final = array();
		// Perform the actual install
		foreach( $toInstall as $key )
			$final[] = $dependencies[$key];

		return $final;
	} // }}}

	function install( Tiki_Profile $profile ) // {{{
	{
		global $cachelib;
		require_once 'lib/cache/cachelib.php';

		if( ! $profiles = $this->getInstallOrder( $profile ) )
			return false;

		foreach( $profiles as $p )
			$this->doInstall( $p );
		
		if (count($this->getFeedback()) == count($profiles)) {
			$this->setFeedback(tra('Nothing was installed, check profile for errors'));
		}
		$cachelib->empty_full_cache();
		return true;
	} // }}}

	function isInstalled( Tiki_Profile $profile ) // {{{
	{
		return array_key_exists( $profile->getProfileKey(), $this->installed );
	} // }}}

	function isKeyInstalled( $domain, $profile ) // {{{
	{
		return array_key_exists( Tiki_Profile::getProfileKeyFor( $domain, $profile ), $this->installed );
	} // }}}

	function isInstallable( Tiki_Profile $profile ) // {{{
	{
		foreach( $profile->getObjects() as $object )
		{
			$handler = $this->getInstallHandler( $object );
			if( ! $handler )
				throw new Exception( "No handler found for object type {$object->getType()} in {$profile->domain}:{$profile->profile}" );

			if( ! $handler->canInstall() )
				throw new Exception( "Object (#{$object->getRef()}) of type {$object->getType()} in {$profile->domain}:{$profile->profile} does not validate" );
		}<commit_msg>[FIX] Add exception catch<commit_after><?php

class Tiki_Profile_Installer
{
	private $installed = array();
	private $handlers = array(
		'tracker' => 'Tiki_Profile_InstallHandler_Tracker',
		'tracker_field' => 'Tiki_Profile_InstallHandler_TrackerField',
		'tracker_item' => 'Tiki_Profile_InstallHandler_TrackerItem',
		'wiki_page' => 'Tiki_Profile_InstallHandler_WikiPage',
		'category' => 'Tiki_Profile_InstallHandler_Category',
		'file_gallery' => 'Tiki_Profile_InstallHandler_FileGallery',
		'module' => 'Tiki_Profile_InstallHandler_Module',
		'menu' => 'Tiki_Profile_InstallHandler_Menu',
		'blog' => 'Tiki_Profile_InstallHandler_Blog',
		'blog_post' => 'Tiki_Profile_InstallHandler_BlogPost',
		'plugin_alias' => 'Tiki_Profile_InstallHandler_PluginAlias',
		'webservice' => 'Tiki_Profile_InstallHandler_Webservice',
		'webservice_template' => 'Tiki_Profile_InstallHandler_WebserviceTemplate',
		'rss' => 'Tiki_Profile_InstallHandler_Rss',
		'topic' => 'Tiki_Profile_InstallHandler_Topic',
		'article_type' => 'Tiki_Profile_InstallHandler_ArticleType',
		'article' => 'Tiki_Profile_InstallHandler_Article',
		'forum' => 'Tiki_Profile_InstallHandler_Forum',
		'template' => 'Tiki_Profile_InstallHandler_Template',
		'perspective' => 'Tiki_Profile_InstallHandler_Perspective',
		'users' => 'Tiki_Profile_UsersHandler',
	);

	private static $typeMap = array(
		'wiki_page' => 'wiki page',
		'file_gallery' => 'fgal',
	);

	private $userData = false;
	
	private $feedback = array();	// Let users know what's happened

	/**
	 * @param $feed - (strings append, array replaces) lines of feedback text
	 * @return none
	 */
	function setFeedback( $feed ) {
		if (is_array( $feed )) {
			$this->feedback = $feed;
		} else {
			$this->feedback[] = $feed;
		}
	}
	
	/**
	 * @param $index - (int) index of feedback string to return if present
	 * @return string or whole array if no index specified 
	 */
	function getFeedback( $index ) {
		if (isset( $index ) && $index < count($this->feedback) ) {
			return $this->feedback[ $index ];
		} else {
			return $this->feedback;
		}
	}
	
	public static function convertType( $type ) // {{{
	{
		if( array_key_exists( $type, self::$typeMap ) )
			return self::$typeMap[$type];
		else
			return $type;
	} // }}}

	public static function convertObject( $type, $id ) // {{{
	{
		global $tikilib;

		if( $type == 'wiki page' && is_numeric( $id ) )
			return $tikilib->get_page_name_from_id( $id );
		else
			return $id;
	} // }}}

	function __construct() // {{{
	{
		global $tikilib;

		$result = $tikilib->query( "SELECT DISTINCT domain, profile FROM tiki_profile_symbols" );
		if ( $result ) while( $row = $result->fetchRow() )
			$this->installed[Tiki_Profile::getProfileKeyFor( $row['domain'], $row['profile'] )] = true;
	} // }}}

	function setUserData( $userData ) // {{{
	{
		$this->userData = $userData;
	} // }}}

	function getInstallOrder( Tiki_Profile $profile ) // {{{
	{
		// Obtain the list of all required profiles
		$dependencies = $profile->getRequiredProfiles(true);
		$dependencies[$profile->getProfileKey()] = $profile;

		$referenced = array();
		$knownObjects = array();
		foreach( Tiki_Profile_Object::getNamedObjects() as $o )
			$knownObjects[] = Tiki_Profile_Object::serializeNamedObject( $o );

		// Build the list of dependencies for each profile
		$short = array();
		foreach( $dependencies as $key => $profile )
		{
			$short[$key] = array();
			foreach( $profile->getRequiredProfiles() as $k => $p )
				$short[$key][] = $k;

			foreach( $profile->getNamedObjects() as $o )
				$knownObjects[] = Tiki_Profile_Object::serializeNamedObject( $o );
			foreach( $profile->getReferences() as $o )
				$referenced[] = Tiki_Profile_Object::serializeNamedObject( $o );

			if( ! $this->isInstallable( $profile ) )
				return false;
		}

		// Make sure all referenced objects actually exist
		$remain = array_diff( $referenced, $knownObjects );
		if( ! empty( $remain ) )
			throw new Exception( "Unknown objects are referenced: " . implode( ', ', $remain ) );

		// Build the list of packages that need to be installed
		$toSequence = array();
		foreach( $dependencies as $key => $profile )
			if( ! $this->isInstalled( $profile ) )
				$toSequence[] = $key;

		// Order the packages to make sure all dependencies are met
		$toInstall = array();
		$counter = 0;
		while( count( $toSequence ) )
		{
			// If all packages were tested and no order was found, exit
			// Probably means there is a circular dependency
			if( $counter++ > count( $toSequence ) * 2 )
				throw new Exception( "Profiles could not be ordered: " . implode( ", ", $toSequence ) );

			$key = reset( $toSequence );

			// Remove packages that are already scheduled or installed from dependencies
			$short[$key] = array_diff( $short[$key], array_keys( $this->installed ), $toInstall );

			$element = array_shift( $toSequence );
			if( count( $short[$key] ) )
				$toSequence[] = $element;
			else
			{
				$counter = 0;
				$toInstall[] = $element;
			}
		}

		$final = array();
		// Perform the actual install
		foreach( $toInstall as $key )
			$final[] = $dependencies[$key];

		return $final;
	} // }}}

	function install( Tiki_Profile $profile ) // {{{
	{
		global $cachelib;
		require_once 'lib/cache/cachelib.php';

		try {
			if( ! $profiles = $this->getInstallOrder( $profile ) )
				return false;
	
			foreach( $profiles as $p )
				$this->doInstall( $p );
			
			if (count($this->getFeedback()) == count($profiles)) {
				$this->setFeedback(tra('Nothing was installed, check profile for errors'));
			}
			$cachelib->empty_full_cache();
			return true;
		
		} catch(Exception $e) {
			$this->setFeedback(tra('An error occurred: ') . $e->getMessage());
			return false;
		}

	} // }}}

	function isInstalled( Tiki_Profile $profile ) // {{{
	{
		return array_key_exists( $profile->getProfileKey(), $this->installed );
	} // }}}

	function isKeyInstalled( $domain, $profile ) // {{{
	{
		return array_key_exists( Tiki_Profile::getProfileKeyFor( $domain, $profile ), $this->installed );
	} // }}}

	function isInstallable( Tiki_Profile $profile ) // {{{
	{
		foreach( $profile->getObjects() as $object )
		{
			$handler = $this->getInstallHandler( $object );
			if( ! $handler )
				throw new Exception( "No handler found for object type {$object->getType()} in {$profile->domain}:{$profile->profile}" );

			if( ! $handler->canInstall() )
				throw new Exception( "Object (#{$object->getRef()}) of type {$object->getType()} in {$profile->domain}:{$profile->profile} does not validate" );
		}
{'fraction_non_alphanumeric': 0.15868217054263567, 'fraction_numerical': 0.00046511627906976747, 'mean_word_length': 4.137793707686181, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 131, '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': '3370705', 'n_tokens_mistral': 4680, 'n_tokens_neox': 4164, 'n_words': 990}