Invision Power Services, Inc. * @copyright (c) 2001 - 2016 Invision Power Services, Inc. * @license http://www.invisionpower.com/legal/standards/ * @package IPS Community Suite * @since 18 Feb 2013 * @version SVN_VERSION_NUMBER */ namespace IPS\Application; /* To prevent PHP errors (extending class does not exist) revealing path */ if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) ) { header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' ); exit; } /** * @brief Node class for Modules */ class _Module extends \IPS\Node\Model implements \IPS\Node\Permissions { /** * @brief [ActiveRecord] Multiton Store */ protected static $multitons; /** * @brief [ActiveRecord] Database Table */ public static $databaseTable = 'core_modules'; /** * @brief [ActiveRecord] Database Prefix */ public static $databasePrefix = 'sys_module_'; /** * @brief [ActiveRecord] Database ID Fields */ protected static $databaseIdFields = array( 'sys_module_key' ); /** * @brief [ActiveRecord] Multiton Map */ protected static $multitonMap = array(); /** * @brief [Node] Parent Node ID Database Column */ public static $parentNodeColumnId = 'application'; /** * @brief [Node] Parent Node Class */ public static $parentNodeClass = 'IPS\Application'; /** * @brief [Node] Node Title */ public static $nodeTitle = 'applications_and_modules'; /** * @brief [Node] Order Database Column */ public static $databaseColumnOrder = 'position'; /** * @brief [Node] Enabled/Disabled Column */ public static $databaseColumnEnabledDisabled = 'visible'; /** * @brief [Node] App for permission index */ public static $permApp = 'core'; /** * @brief [Node] Type for permission index */ public static $permType = 'module'; /** * @brief [Node] Prefix string that is automatically prepended to permission matrix language strings */ public static $permissionLangPrefix = 'module_'; /** * @brief [Node] ACP Restrictions */ protected static $restrictions = array( 'app' => 'core', 'module' => 'applications', 'all' => 'module_manage' ); /** * @brief [Node] Sortable? */ public static $nodeSortable = FALSE; /** * @brief All modules */ protected static $modules = NULL; /** * Get Modules * * @return array */ public static function modules() { if( static::$modules === NULL ) { if ( isset( \IPS\Data\Store::i()->modules ) ) { $rows = \IPS\Data\Store::i()->modules; } else { $rows = iterator_to_array( \IPS\Db::i()->select( '*', 'core_modules', NULL, 'sys_module_position' )->join( 'core_permission_index', array( "core_permission_index.app=? AND core_permission_index.perm_type=? AND core_permission_index.perm_type_id=core_modules.sys_module_id", 'core', 'module' ) ) ); \IPS\Data\Store::i()->modules = $rows; } static::$modules = array(); foreach ( $rows as $row ) { static::$modules[ $row['sys_module_application'] ][ $row['sys_module_area'] ][ $row['sys_module_key'] ] = static::constructFromData( $row ); } } return static::$modules; } /** * Get a module * * @param string $app * @param string $key * @param string|NULL $area * @return \IPS\Application\Module * @throws \OutOfRangeException */ public static function get( $app, $key, $area=NULL ) { $modules = static::modules(); if ( isset( $modules[ $app ] ) ) { $area = $area ?: \IPS\Dispatcher::i()->controllerLocation; if ( isset( $modules[ $app ][ $area ] ) ) { if ( isset( $modules[ $app ][ $area ][ $key ] ) ) { return $modules[ $app ][ $area ][ $key ]; } } } throw new \OutOfRangeException; } /** * Set module as default for this area * * @return void */ public function setAsDefault() { \IPS\Db::i()->update( 'core_modules', array( 'sys_module_default' => 0 ), array( 'sys_module_area=? AND sys_module_application=?', $this->area, $this->application ) ); \IPS\Db::i()->update( 'core_modules', array( 'sys_module_default' => 1 ), array( 'sys_module_id=?', $this->id ) ); unset( \IPS\Data\Store::i()->modules ); /* Clear guest page caches */ \IPS\Data\Cache::i()->clearAll(); } /** * Search * * @param string $column Column to search * @param string $query Search query * @param string|null $order Column to order by * @param mixed $where Where clause * @return array */ public static function search( $column, $query, $order=NULL, $where=array() ) { if ( $column === '_title' ) { $return = array(); foreach( \IPS\Member::loggedIn()->language()->words as $k => $v ) { if ( preg_match( '/^module__([a-z]*)_([a-z]*)$/', $k, $matches ) and mb_strpos( mb_strtolower( $v ), mb_strtolower( $query ) ) !== FALSE ) { try { $module = static::load( $matches[2], 'sys_module_key', count( $where ) ? array_merge( array( array( 'sys_module_application=?', $matches[1] ) ), array( $where ) ) : array( array( 'sys_module_application=?', $matches[1] ) ) ); $return[ $module->_id ] = $module; } catch ( \OutOfRangeException $e ) { } } } return $return; } return parent::search( $column, $query, $order, $where ); } /** * [Node] Get buttons to display in tree * Example code explains return value * * @code array( array( 'icon' => array( 'icon.png' // Path to icon 'core' // Application icon belongs to ), 'title' => 'foo', // Language key to use for button's title parameter 'link' => \IPS\Http\Url::internal( 'app=foo...' ) // URI to link to 'class' => 'modalLink' // CSS Class to use on link (Optional) ), ... // Additional buttons ); * @endcode * @param string $url Base URL * @param bool $subnode Is this a subnode? * @return array */ public function getButtons( $url, $subnode=FALSE ) { $buttons = array(); if( $this->canManagePermissions() ) { $buttons['permissions'] = array( 'icon' => 'lock', 'title' => 'permissions', 'link' => "{$url}&do=permissions&id={$this->_id}" . ( $subnode ? '&subnode=1' : '' ), 'data' => array( 'ipsDialog' => '', 'ipsDialog-title' => \IPS\Member::loggedIn()->language()->addToStack('permissions') ) ); } $buttons['default'] = array( 'icon' => $this->default ? 'star' : 'star-o', 'title' => 'make_default_module', 'link' => $url . "&do=setDefaultModule&id={$this->_id}&default=1", ); return $buttons; } /** * [Node] Get Node Title * * @return string */ protected function get__title() { $key = "module__{$this->application}_{$this->key}"; return \IPS\Member::loggedIn()->language()->addToStack( $key ); } /** * [Node] Get the title to store in the log * * @return string|null */ public function titleForLog() { try { return \IPS\Lang::load( \IPS\Lang::defaultLanguage() )->get( "module__{$this->application}_{$this->key}" ); } catch ( \UnderflowException $e ) { return $this->_title; } } /** * [Node] Get Node Icon * * @return string */ protected function get__icon() { return 'cube'; } /** * [Node] Get whether or not this node is locked to current enabled/disabled status * * @note Return value NULL indicates the node cannot be enabled/disabled * @return bool|null */ protected function get__locked() { return $this->protected; } /** * [Node] Does the currently logged in user have permission to add a child node? * * @return bool * @note Modules don't really have "child nodes". Controllers are not addable via the ACP. */ public function canAdd() { return false; } /** * [Node] Does the currently logged in user have permission to edit permissions for this node? * * @return bool */ public function canManagePermissions() { if ( $this->protected ) { return FALSE; } return parent::canManagePermissions(); } /** * [Node] Does this node have children? * * @param string|NULL $permissionCheck The permission key to check for or NULl to not check permissions * @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member * @param bool $subnodes Include subnodes? * @param mixed $_where Additional WHERE clause * @return bool */ public function hasChildren( $permissionCheck='view', $member=NULL, $subnodes=TRUE, $_where=array() ) { return false; } /** * [Node] Fetch Child Nodes * * @param string|NULL $permissionCheck The permission key to check for or NULL to not check permissions * @param \IPS\Member|NULL $member The member to check permissions for or NULL for the currently logged in member * @param bool $subnodes Include subnodes? * @param array|NULL $skip Children IDs to skip * @param mixed $_where Additional WHERE clause * @return array */ public function children( $permissionCheck='view', $member=NULL, $subnodes=TRUE, $skip=null, $_where=array() ) { return array(); } /** * [Node] Add/Edit Form * * @param \IPS\Helpers\Form $form The form * @return void */ public function form( &$form ){} /** * Save * * @param bool $skipMember Skip clearing member cache clearing * @return void */ public function save( $skipMember=FALSE ) { $new = $this->_new; parent::save(); if ( $new ) { \IPS\Db::i()->insert( 'core_permission_index', array( 'app' => 'core', 'perm_type' => 'module', 'perm_type_id' => $this->id, 'perm_view' => '*', ) ); } /* Clear caches */ if( !$skipMember ) { \IPS\Member::clearCreateMenu(); } unset( \IPS\Data\Store::i()->modules ); } /** * [Node] Delete the theme set * * @return void */ public function delete() { parent::delete(); \IPS\Member::clearCreateMenu(); unset( \IPS\Data\Store::i()->modules ); } }