Module.php #1

  • //
  • guest/
  • perforce_software/
  • chronicle/
  • main/
  • library/
  • P4Cms/
  • Module.php
  • View
  • Commits
  • Open Download .zip Download (31 KB)
<?php
/**
 * Modules are containers for functionality. The module model
 * provides access to modules so that they can be listed and
 * interrogated. Module models are read-only.
 *
 * Modules may contain a static module class 'Module.php', (aka
 * the module integration class) which can provide functionality
 * and integrate the module with the rest of the system. The
 * module integration class name should be begin with the name of
 * the module, followed by an underscore and the word Module
 * (e.g. 'Foo_Module').
 *
 * To use modules, you are required to indicate where "core"
 * modules reside via the setCoreModulesPath() method.
 * Additional paths can be added via addPackagesPath(). The
 * order that paths are added is significant. If a module
 * exists in two or more paths, the path that was added last
 * takes precedence, unless it is a core module. Core modules
 * are always loaded from the core modules path.
 *
 * @copyright   2011 Perforce Software. All rights reserved.
 * @license     Please see LICENSE.txt in top-level folder of this distribution.
 * @version     <release>/<patch>
 */
class P4Cms_Module extends P4Cms_PackageAbstract
{
    const               PACKAGE_FILENAME    = 'module.ini';
    const               CONFIG_RECORD_PATH  = 'config/module';

    protected           $_configRecord      = null;
    protected           $_configFolderName  = 'module';

    protected static    $_idField           = 'name';
    protected static    $_coreModulesPath   = null;
    protected static    $_packagesPaths     = array();
    protected static    $_configRecords     = null;
    protected static    $_isInitialized     = array();
    protected static    $_isLoaded          = array();
    protected static    $_dependencyTypes   = array('library', 'module');

    protected static    $_fields            = array(
        'name'              => array(
            'accessor'      => 'getName',
            'mutator'       => 'setName'
        ),
        'label'             => array(
            'accessor'      => 'getLabel',
            'mutator'       => 'readOnly'
        ),
        'core'              => array(
            'accessor'      => 'isCoreModule',
            'mutator'       => 'readOnly'
        ),
        'enabled'           => array(
            'accessor'      => 'isEnabled',
            'mutator'       => 'readOnly'
        ),
        'configurable'      => array(
            'accessor'      => 'isConfigurable',
            'mutator'       => 'readOnly'
        ),
        'configUri'         => array(
            'accessor'      => 'getConfigUri',
            'mutator'       => 'readOnly'
        ),
        'version'           => array(
            'accessor'      => 'getVersion',
            'mutator'       => 'readOnly'
        ),
        'description'       => array(
            'accessor'      => 'getDescription',
            'mutator'       => 'readOnly'
        ),
        'maintainerInfo'    => array(
            'accessor'      => 'getMaintainerInfo',
            'mutator'       => 'readOnly'
        ),
        'dependencies'      => array(
            'accessor'      => 'getDependencies',
            'mutator'       => 'readOnly'
        ),
        'tags'              => array(
            'accessor'      => 'getTags',
            'mutator'       => 'readOnly'
        )
    );

    /**
     * Throws read-only exceptions on behalf of most mutators.
     *
     * @throws  P4Cms_Module_Exception  Every time; configured for specific mutators.
     */
    public function readOnly()
    {
        throw new P4Cms_Module_Exception('P4Cms_Module is primarily a read-only class.');
    }

    /**
     * Set the full path to the package folder.
     * Extends parent to ensure that basename is valid in a class name.
     *
     * @param   string  $path           the full path to the package folder.
     * @return  P4Cms_PackageAbstract   provides fluent interface.
     */
    public function setPath($path)
    {
        // validate module name - only allow characters valid in a class name.
        if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', basename($path))) {
            throw new P4Cms_Module_Exception(
                "Invalid module ('" . $name . "'). "
               . "The module name contains illegal characters."
           );
        }

        return parent::setPath($path);
    }

    /**
     * Get the name of this package.
     * Extends parent to upper-case the first letter.
     *
     * @return  string  the name of this package.
     */
    public function getName()
    {
        return ucfirst(parent::getName());
    }

    /**
     * Set the name of this package.
     *
     * @param   string  $name   The new name to use.
     * @return  P4Cms_Module    To maintain a fluent interface.
     */
    public function setName($name)
    {
        return $this->_setValue('name');
    }

    /**
     * Get the url to this module's resources folder.
     *
     * @return  string  the base url for this module's resources.
     */
    public function getBaseUrl()
    {
        return parent::getBaseUrl() . '/resources';
    }

    /**
     * Get any routes configured for this module.
     *
     * @return  array   list of routes from module.ini.
     */
    public function getRoutes()
    {
        $info = $this->getPackageInfo();
        return isset($info['routes']) && is_array($info['routes']) ? $info['routes'] : array();
    }

    /**
     * Get all core modules.
     *
     * @return  P4Cms_Model_Iterator    all core modules.
     */
    public static function fetchAllCore()
    {
        $modules = new P4Cms_Model_Iterator;
        foreach (static::fetchAll() as $module) {
            if ($module->isCoreModule()) {
                $modules[] = $module;
            }
        }
        return $modules;
    }

    /**
     * Get all modules that are enabled - includes core modules
     * unless $excludeCoreModules is set to true.
     *
     * @param   bool    $excludeCoreModules optional - defaults to false - set to true to
     *                                      exclude core modules from the set of returned modules.
     * @return  P4Cms_Model_Iterator        all enabled modules.
     */
    public static function fetchAllEnabled($excludeCoreModules = false)
    {
        $modules = new P4Cms_Model_Iterator;
        foreach (static::fetchAll() as $module) {
            if ((!$module->isCoreModule() || !$excludeCoreModules) && $module->isEnabled()) {
                $modules[] = $module;
            }
        }
        return $modules;
    }

    /**
     * Get all modules that are disabled.
     *
     * @return  P4Cms_Model_Iterator    all disabled modules.
     */
    public static function fetchAllDisabled()
    {
        $modules = new P4Cms_Model_Iterator;
        foreach (static::fetchAll() as $module) {
            if (!$module->isEnabled()) {
                $modules[] = $module;
            }
        }
        return $modules;
    }

    /**
     * Enable this module for the current site.
     *
     * @return  P4Cms_Module            provides a fluent interface.
     * @throws  P4Cms_Module_Exception  if the module cannot be enabled.
     */
    public function enable()
    {
        // ensure module is disabled.
        $this->_ensureDisabled();

        // ensure dependencies are satisfied.
        if (!$this->areDependenciesSatisfied()) {
            throw new P4Cms_Module_Exception("Can't enable the '" . $this->getName()
                . "' module. One or more dependencies are not satisfied.");
        }

        // enable module by saving its configuration.
        // this will restore the previous config if one exists.
        $this->saveConfig(null, "Enabled '" . $this->getName() . "' module.");

        // initialize the module in the environment.
        $this->init();
        try {
            if ($this->hasIntegrationMethod('enable')) {
                $this->callIntegrationMethod('enable');
            }
        } catch (Exception $e) {
            $message = "Failed to enable the '" . $this->getName() . "' module.";
            P4Cms_Log::logException($message, $e);

            $this->disable();
            throw new P4Cms_Module_Exception($message);
        }

        return $this;
    }

    /**
     * Disable this module.
     *
     * @return  P4Cms_Module            provides fluent interface.
     * @throws  P4Cms_Module_Exception  if the module cannot be disabled.
     */
    public function disable()
    {
        // ensure module is enabled to begin with.
        $this->_ensureEnabled();

        // ensure module is not a core module.
        if ($this->isCoreModule()) {
            throw new P4Cms_Module_Exception("The '" . $this->getName()
                . "' module is a core module. Core modules cannot be disabled.");
        }

        // ensure dependencies are respected.
        if ($this->hasDependents()) {
            throw new P4Cms_Module_Exception("Can't disable the '" . $this->getName()
                . "' module. One or more enabled modules depend upon it.");
        }

        // call the 'disable' integration method if defined.
        if ($this->hasIntegrationMethod('disable')) {
            $this->callIntegrationMethod('disable');
        }

        // disable module by deleting config record.
        if ($this->_hasStoredConfigRecord()) {
            $this->_getConfigRecord()->delete("Disabled '" . $this->getName() . "' module.");
            unset(static::$_configRecords[$this->getName()]);
        }

        return $this;
    }

    /**
     * Check if this module is enabled.
     * A module is considered enabled if it has a config record in storage.
     *
     * @return  boolean     true if the module is enabled.
     */
    public function isEnabled()
    {
        // core modules are always enabled.
        if ($this->isCoreModule()) {
            return true;
        }

        // check for stored config record.
        return $this->_hasStoredConfigRecord();
    }

    /**
     * Check if the module can be enabled.
     *
     * @return  bool    true if the module can be enabled.
     */
    public function canEnable()
    {
        if ($this->isCoreModule() || $this->isEnabled() || !$this->areDependenciesSatisfied()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Check if the module can be disabled.
     *
     * @return  bool    true if the module can be disabled.
     */
    public function canDisable()
    {
        if ($this->isCoreModule() || !$this->isEnabled() || $this->hasDependents()) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Determine if all of the module dependencies are satisfied and
     * the module can be enabled.
     *
     * @return  boolean     true if all of the required modules are installed and enabled.
     */
    public function areDependenciesSatisfied()
    {
        // if no dependencies, can be enabled.
        if (!$this->hasDependencies()) {
            return true;
        }

        // check if required modules are installed and enabled.
        foreach ($this->getDependencies() as $dependency) {
            extract($dependency);
            if (!static::isDependencySatisfied($name, $type, $versions)) {
                return false;
            }
        }

        // all dependencies are satisfied - can enable!
        return true;
    }

    /**
     * Determine if the module has any dependencies.
     *
     * @return  boolean     true if the module has dependencies.
     */
    public function hasDependencies()
    {
        return (bool) count($this->getDependencies());
    }

    /**
     * Determine if any other enabled modules depend upon this module.
     *
     * @return  boolean     true if other enabled modules depend on this module.
     */
    public function hasDependents()
    {
        // check if any enabled modules are dependent on this module.
        foreach (P4Cms_Module::fetchAllEnabled() as $module) {
            if (!$module->hasDependencies()) {
                continue;
            }
            $dependencies = $module->getDependencies();
            foreach ($dependencies as $dependency) {
                if ($dependency['type'] === 'module'
                    && $dependency['name'] == $this->getName()
                ) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Check if the given dependency is satisified.
     *
     * Versions may be specified using wildcards such as '*' and '?'.
     * Matching is performed using fnmatch() and therefore supports
     * all of the same shell patterns recognized by that function.
     *
     * @param   string          $name       the name of the required package.
     * @param   string          $type       the type of dependency (module or library)
     * @param   string|array    $versions   suitable versions of the package.
     * @return  bool            true if the correct package is installed/enabled.
     */
    public static function isDependencySatisfied($name, $type, $versions)
    {
        // dependency name and a valid type must be specified.
        if (!isset($name) || !in_array($type, static::$_dependencyTypes)) {
            return false;
        }

        // accept single version string or array of versions.
        $versions = (array) $versions;

        // differentiate module and library dependency checking.
        if ($type === 'library') {
            $className = $name . "_Version";
            if (!class_exists($className)) {
                return false;
            }

            $version = $className::VERSION;
        } else if ($type === 'module') {
            // check if the named module exists.
            if (!P4Cms_Module::exists($name)) {
                return false;
            }

            // fetch the named module and check if it's enabled.
            $module = P4Cms_Module::fetch($name);
            if (!$module->isEnabled()) {
                return false;
            }

            $version = $module->getVersion();
        }

        // check version.
        foreach ($versions as $suitableVersion) {
            if (fnmatch($suitableVersion, $version)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get the name of the corresponding integration class for this module.
     *
     * @return  string  the name of the integration class.
     */
    public function getIntegrationClassName()
    {
        return $this->getName() . '_Module';
    }

    /**
     * Determine if this module is a core module.
     *
     * @return  bool    true if this module is a core (required) module.
     */
    public function isCoreModule()
    {
        return (dirname($this->getPath()) == $this->getCoreModulesPath());
    }

    /**
     * Set the path to the core modules.
     *
     * @param   string  $path   the path to the core modules.
     */
    public static function setCoreModulesPath($path)
    {
        static::$_coreModulesPath = $path;
    }

    /**
     * Get the path to the core modules.
     *
     * @return  string  the path that contains the core modules.
     */
    public static function getCoreModulesPath()
    {
        if (!static::$_coreModulesPath) {
            throw new P4Cms_Module_Exception("Can't get core modules. Path is unset.");
        }
        return static::$_coreModulesPath;
    }

    /**
     * Extends parent to add core modules path last.
     *
     * @return  array   the list of paths that can contain packages.
     */
    public static function getPackagesPaths()
    {
        $paths   = static::$_packagesPaths;
        $paths[] = static::getCoreModulesPath();
        return $paths;
    }

    /**
     * Get any dependencies that this module has on other packages.
     *
     * @return  array   list of dependencies - each entry contains three elements:
     *                      - name     (name of package)
     *                      - type     (type of package)
     *                      - versions (list of suitable versions)
     */
    public function getDependencies()
    {
        $info = $this->getPackageInfo();
        if (!isset($info['dependencies']) || !is_array($info['dependencies'])) {
            return array();
        }

        // normalize/flatten dependencies.
        $dependencies = array();
        foreach (static::$_dependencyTypes as $type) {
            if (!isset($info['dependencies'][$type]) || !is_array($info['dependencies'][$type])) {
                continue;
            }

            // convert comma-separated version list to array form.
            foreach ($info['dependencies'][$type] as $name => $versions) {
                $dependencies[] = array(
                    'name'      => $name,
                    'type'      => $type,
                    'versions'  => str_getcsv($versions, ',')
                );
            }
        }

        return $dependencies;
    }

    /**
     * Initialize the module in the environment.
     *
     * This method only needs to be called once per-module, per-request.
     * to register the module with the application.
     *
     * @return  P4Cms_Module    provides fluent interface.
     */
    public function init()
    {
        // don't initialize modules twice
        if ($this->_isInitialized()) {
            return $this;
        }

        // an instance of the view is required to properly initialize a module.
        if (!Zend_Layout::getMvcInstance()) {
            Zend_Layout::startMvc();
        }
        $view = Zend_Layout::getMvcInstance()->getView();
        if (!$view instanceof Zend_View) {
            throw new P4Cms_Module_Exception("Can't initialize module. Failed to get view instance.");
        }

        // add module to loader so that module classes will auto-load.
        P4Cms_Loader::addPackagePath($this->getName(), $this->getPath());

        // add module's controllers directory to front controller so that requests will route.
        Zend_Controller_Front::getInstance()->addControllerDirectory(
            $this->getPath() . '/controllers',
            basename($this->getPath())
        );

        // each module can have layouts - add layout script path.
        if (is_dir($this->getPath() . '/layouts/scripts')) {
            $view->addScriptPath($this->getPath() . '/layouts/scripts');
        }

        // each module can have helpers (under views or layouts) - add helper paths.
        if (is_dir($this->getPath() . '/views/helpers')) {
            $view->addHelperPath(
                $this->getPath() . '/views/helpers/',
                $this->getName() . '_View_Helper_'
            );
        }
        if (is_dir($this->getPath() . '/layouts/helpers')) {
            $view->addHelperPath(
                $this->getPath() . '/layouts/helpers/',
                $this->getName() . '_View_Helper_'
            );
        }

        // each module can have form plugins:
        // elements, decorators, validators and filters.
        $plugins = array(
            array(Zend_Form::ELEMENT,           '/forms/elements/',     'Form_Element'),
            array(Zend_Form::DECORATOR,         '/forms/decorators/',   'Form_Decorator'),
            array(Zend_Form_Element::VALIDATE,  '/validators/',         'Validate'),
            array(Zend_Form_Element::FILTER,    '/filters/',            'Filter')
        );
        foreach ($plugins as $plugin) {
            if (is_dir($this->getPath() . $plugin[1])) {
                P4Cms_Form::registerPrefixPath(
                    $this->getName() . "_" . $plugin[2],
                    $this->getPath() . $plugin[1],
                    $plugin[0]
                );
            }
        }

        // each module can have controller action helpers (under controllers)
        if (is_dir($this->getPath() . '/controllers/helpers')) {
            Zend_Controller_Action_HelperBroker::addPath(
                $this->getPath() . '/controllers/helpers/',
                $this->getName() . '_Controller_Helper_'
            );
        }

        // call the 'init' integration method if defined.
        try {
            if ($this->hasIntegrationMethod('init')) {
                $this->callIntegrationMethod('init');
            }
        } catch (Exception $e) {
            P4Cms_Log::logException("Failed to init the '" . $this->getName() . "' module.", $e);
        }

        // flag the module as initialized
        $this->_setInitialized();

        return $this;
    }

    /**
     * Attempt to load this module
     *
     * @return  P4Cms_Module    provides fluent interface.
     * @todo    Consider moving guts of this to init() as it isn't clear why
     *          stylesheets, scripts, dojo modules and routes are added here and
     *          not during init - we should keep load() for third-party modules.
     */
    public function load()
    {
        // don't load modules twice (without unloading first)
        if ($this->isLoaded()) {
            return $this;
        }

        // add module meta, stylesheets and scripts to view.
        $this->_loadHtmlMeta();
        $this->_loadStylesheets();
        $this->_loadScripts();

        // load dojo components.
        $this->_loadDojo();

        // if the module is a route provider add the routes to the router.
        $router = Zend_Controller_Front::getInstance()->getRouter();
        $router->addConfig(new Zend_Config($this->getRoutes()));

        try {
            if ($this->hasIntegrationMethod('load')) {
                $this->callIntegrationMethod('load');
            }
            $this->_setLoaded();
        } catch (Exception $e) {
            P4Cms_Log::logException("Failed to load the '" . $this->getName() . "' module.", $e);
        }

        return $this;
    }

    /**
     * Determine if this module has a corresponding static module integration class.
     *
     * @return  boolean     true if the module has a corresponding module integration class.
     */
    public function hasIntegrationClass()
    {
        if (is_file($this->getPath() . '/Module.php') &&
            class_exists($this->getIntegrationClassName())) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * Determine whether an integration class method exists.
     *
     * @param  string  $method  the name of the method to find.
     */
    public function hasIntegrationMethod($method)
    {
        if (!$this->hasIntegrationClass()) {
            return false;
        }
        if (!method_exists($this->getIntegrationClassName(), $method)) {
            return false;
        }
        return true;
    }

    /**
     * Call a static method on the integration class.
     *
     * @param   string  $method     the name of the method to call.
     * @param   array   $params     optional - the arguments to pass to the method.
     * @return  mixed   the return value of the integration method.
     * @throws  P4Cms_Module_Exception if the integration class or method does not exist.
     */
    public function callIntegrationMethod($method, $params = array())
    {
        if (!$this->hasIntegrationClass()) {
            throw new P4Cms_Module_Exception("Can't call integration method: '"
              . $method . "'. " . $this->getName() . " module does not have an integration class.");
        }
        if (!method_exists($this->getIntegrationClassName(), $method)) {
            throw new P4Cms_Module_Exception("Can't call integration method: '"
              . $method . "'. " . $this->getName() . " module does not have this method.");
        }
        return call_user_func_array(array($this->getIntegrationClassName(), $method), $params);
    }

    /**
     * Determine if this module is configurable.
     * Considered configurable if the module.ini file specifies
     * a configure controller.
     *
     * @return  boolean     true if the module is configurable.
     */
    public function isConfigurable()
    {
        $info = $this->getPackageInfo();
        return isset($info['configure']['controller']) && is_array($info['configure']);
    }

    /**
     * Get the URI to configure this module.
     *
     * @return  string  the URI to configure this module.
     */
    public function getConfigUri()
    {
        if (!$this->isConfigurable()) {
            throw new P4Cms_Module_Exception(
                "Cannot get URI to configure '" . $this->getName() .
                "'. The module is not configurable."
            );
        }

        // return assembled uri.
        $router = Zend_Controller_Front::getInstance()->getRouter();
        return $router->assemble($this->getConfigRouteParams(), null, true);
    }

    /**
     * Get the route params to configure this module.
     *
     * @return  array  the route params to configure this module.
     */
    public function getConfigRouteParams()
    {
        if (!$this->isConfigurable()) {
            throw new P4Cms_Module_Exception(
                "Cannot get URI params to configure '" . $this->getName() .
                "'. The module is not configurable."
            );
        }

        // if no module is specified, default to this module.
        $info           = $this->getPackageInfo();
        $routeParams    = $info['configure'];
        if (!isset($routeParams['module'])) {
            $routeParams['module'] = $this->getRouteFormattedName();
        }

        return $routeParams;
    }

    /**
     * Get the route-formatted name of this module (e.g. foo-bar
     * instead of FooBar).
     *
     * @return  string  the route formatted module name.
     */
    public function getRouteFormattedName()
    {
        return P4Cms_Controller_Router_Route_Module::formatRouteParam(
            $this->getName()
        );
    }

    /**
     * Get the configuration of this module.
     *
     * This returns a Zend_Config object which can contain any
     * configuration information the module developer chooses to
     * store.
     *
     * @return  Zend_Config     the module configuration.
     */
    public function getConfig()
    {
        return $this->_getConfigRecord()->getConfig();
    }

    /**
     * Set the configuration of this module. This does
     * not save the configuration. You must call saveConfig()
     * to store the configuration persistently.
     *
     * @param   Zend_Config     $config     the configuration to set.
     * @return  P4Cms_Module                provides fluent interface.
     * @throws  InvalidArgumentException    if the given config is invalid.
     */
    public function setConfig($config)
    {
        $this->_getConfigRecord()->setConfig($config);

        return $this;
    }

    /**
     * Save the configuration of this module.
     *
     * @param   Zend_Config $config         optional - the configuration to save.
     * @param   string      $description    optional - a description of the change.
     * @return  P4Cms_Module                provides fluent interface.
     * @throws  P4Cms_Record_Exception      if an invalid config object is given.
     */
    public function saveConfig($config = null, $description = null)
    {
        $record = $this->_getConfigRecord();

        // if config is given, set it.
        if ($config) {
            $record->setConfig($config);
        }

        // if no description is given, generate one.
        if (!$description) {
            $description = "Saved configuration for '" . $this->getName() . "' module.";
        }

        // save config record.
        $record->save($description);

        static::$_configRecords[$this->getName()] = $record;

        return $this;
    }

    /**
     * Clear the config records cache.
     */
    public static function clearConfigCache()
    {
        static::$_configRecords = null;
    }

    /**
     * Clear the config cache, modules paths and the list of loaded and initialized modules.
     * This is useful for testing purposes.
     */
    public static function reset()
    {
        static::$_isLoaded          = array();
        static::$_isInitialized     = array();
        static::$_coreModulesPath   = null;
        static::clearPackagesPaths();
        static::clearConfigCache();
    }

    /**
     * Get the flag indicating loaded status.
     */
    public function isLoaded()
    {
        return isset(static::$_isLoaded[$this->getName()]);
    }

    /**
     * Determine if this module has a configuration record in storage.
     * This method will only return true if the record is in storage.
     *
     * @return  bool    true if this module has a config record in storage; false otherwise.
     */
    protected function _hasStoredConfigRecord()
    {
        return array_key_exists($this->getName(), $this->_getConfigRecords());
    }

    /**
     * Get the instance copy of the config record associated with this module.
     * If no record exists in storage, one will be created in memory.
     *
     * @return  P4Cms_Record_Config     instance copy of this module's config record.
     */
    protected function _getConfigRecord()
    {
        // get/make instance copy of config record if necessary.
        if ($this->_configRecord === null) {
            if ($this->_hasStoredConfigRecord()) {
                $records = $this->_getConfigRecords();
                $this->_configRecord = clone $records[$this->getName()];
            } else {
                $this->_configRecord = new P4Cms_Record_Config;
                $this->_configRecord->setId(self::CONFIG_RECORD_PATH . '/' . $this->getName());
            }
        }

        return $this->_configRecord;
    }

    /**
     * Get all module config records from storage.
     *
     * Provides localized cache of records to avoid repeatedly
     * fetching records from Perforce. Records are keyed on module
     * name for quick/easy lookups.
     *
     * @return  P4Cms_Model_Iterator    all module config records.
     */
    protected function _getConfigRecords()
    {
        // only fetch config records once.
        if (static::$_configRecords === null) {
            $records = P4Cms_Record_Config::fetchAll(
                P4Cms_Record_Query::create()->addPath(self::CONFIG_RECORD_PATH .'/...')
            );

            // store records keyed on module name.
            static::$_configRecords = array();
            foreach ($records as $record) {
                static::$_configRecords[basename($record->getId())] = $record;
            }
        }

        return static::$_configRecords;
    }

    /**
     * Ensure that this module is disabled.
     *
     * @throws  P4Cms_Module_Exception  if the module is not disabled.
     */
    protected function _ensureDisabled()
    {
        if ($this->isEnabled()) {
            throw new P4Cms_Module_Exception(
                "The '" . $this->getName() . "' module is not disabled."
            );
        }
    }

    /**
     * Ensure that this module is enabled.
     *
     * @throws  P4Cms_Module_Exception  if the module is not enabled.
     */
    protected function _ensureEnabled()
    {
        if (!$this->isEnabled()) {
            throw new P4Cms_Module_Exception(
                "The '" . $this->getName() . "' module is a not enabled."
            );
        }
    }

    /**
     * Set the flag indicating loaded status.
     */
    private function _setLoaded()
    {
        static::$_isLoaded[$this->getName()] = true;
    }

    /**
     * Set the flag indicating unloaded status.
     */
    private function _setUnloaded()
    {
        static::$_isLoaded[$this->getName()] = false;
    }

    /**
     * Get the flag indicating initialization status.
     */
    private function _isInitialized()
    {
        return isset(static::$_isInitialized[$this->getName()]);
    }

    /**
     * Set the flag indicating initialization status.
     */
    private function _setInitialized()
    {
        static::$_isInitialized[$this->getName()] = true;
    }
}
# Change User Description Committed
#1 16170 perforce_software Move Chronicle files to follow new path scheme for branching.
//guest/perforce_software/chronicle/library/P4Cms/Module.php
#1 8972 Matt Attaway Initial add of the Chronicle source code