コード例 #1
0
ファイル: Core.class.php プロジェクト: nicholasryan/CorePlus
	/**
	 * Load all the components in the system, replacement for the Core.
	 * @throws CoreException
	 */
	private function _loadComponents() {
		// cannot reload components.
		if ($this->_components) return null;

		$this->_components = array();
		$this->_libraries  = array();
		$tempcomponents    = false;
		Core\Utilities\Logger\write_debug('Starting loading of component metadata');

		// If the site is in DEVELOPMENT mode, component caching would probably be a bad idea; ie: the developer probably wants
		// those component files loaded everytime.
		if(DEVELOPMENT_MODE){
			$enablecache = false;
		}
		else{
			$enablecache = true;
		}

		// Is there a cache of elements available?  This is a primary system cache that greatly increases performance,
		// since it will no longer have to run through each component.xml file to register each one.
		if($enablecache){
			Core\Utilities\Logger\write_debug('Checking core-components cache');
			// Try to load up the cached components and check them first.
			$tempcomponents = \Core\Cache::Get('core-components', (3600 * 24));

			if($tempcomponents !== false){
				// Cached components only need to be loaded.
				foreach ($tempcomponents as $c) {
					try {
						$c->load();
					}
					catch (Exception $e) {
						// Don't completely bail out here, just invalidate the cache and continue on.
						\Core\Cache::Delete('core-components');
						$tempcomponents = false;
					}
				}
			}
		}


		if(!$enablecache || $tempcomponents == false){
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Scanning for component.xml files manually');
			Core\Utilities\Logger\write_debug('Scanning for component.xml files manually');

			// Core is first, (obviously)
			$tempcomponents['core'] = ComponentFactory::Load(ROOT_PDIR . 'core/component.xml');
			Core\Utilities\Logger\write_debug('Core component loaded');

			// First, build my cache of components, regardless if the component is installed or not.
			$dh = opendir(ROOT_PDIR . 'components');
			if (!$dh) throw new CoreException('Unable to open directory [' . ROOT_PDIR . 'components/] for reading.');

			// This will read through every directory in 'components', which is
			// where all components in the system are installed to.
			while (($file = readdir($dh)) !== false) {
				// skip hidden directories.
				if ($file{0} == '.') continue;

				// skip non-directories
				if (!is_dir(ROOT_PDIR . 'components/' . $file)) continue;

				// Skip directories that do not have a readable component.xml file.
				if (!is_readable(ROOT_PDIR . 'components/' . $file . '/component.xml')) continue;

				//Core\Utilities\Logger\write_debug(' * Loading component ' . $file);
				$c = ComponentFactory::Load(ROOT_PDIR . 'components/' . $file . '/component.xml');
				Core\Utilities\Logger\write_debug('Opened component ' . $file);

				// All further operations are case insensitive.
				// The original call to Component needs to be case sensitive because it sets the filename to pull.
				$file = strtolower($file);

				// If the component was flagged as invalid.. just skip to the next one.
				if (!$c->isValid()) {
					if (DEVELOPMENT_MODE) {
						\Core\set_message('Component ' . $c->getName() . ' appears to be invalid.');
					}
					continue;
				}


				$tempcomponents[$file] = $c;
				unset($c);
			}
			closedir($dh);
			\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Component XML files scanned');

			// Now I probably could actually load the components!

			foreach ($tempcomponents as $c) {
				/** @var Component_2_1 $c */
				try {
					// Load some of the data in the class so that it's available in the cached version.
					// This is because the component 2.1 has built-in caching for many of the XML requests.
					// by calling them once, that lookup data is cached in that component, which in turn gets
					// copied to the cache version here!
					$c->load();
					$c->getClassList();
					$c->getViewSearchDir();
					$c->getSmartyPluginDirectory();
					$c->getWidgetList();
				}
				catch (Exception $e) {
					var_dump($e);
					die();
				}
			}

			// Cache this list!
			if($enablecache){
				Core\Utilities\Logger\write_debug(' * Caching core-components for next pass');
				\Core\Cache::Set('core-components', $tempcomponents, (3600 * 24));
			}
		}

		$list = $tempcomponents;

		\Core\Utilities\Profiler\Profiler::GetDefaultProfiler()->record('Component metadata loaded, starting registration');
		Core\Utilities\Logger\write_debug(' * Component metadata loaded, starting registration');

		// The core component at a minimum needs to be loaded and registered.
		//		$this->_registerComponent($list['core']);
		//		$this->_components['core']->loadFiles();
		//		unset($list['core']);

		// Now that I have a list of components available, copy them into a list of 
		//	components that are installed.

		do {
			$size = sizeof($list);
			foreach ($list as $n => $c) {
				/** @var $c Component_2_1 */

				// Disabled components don't get recognized.
				if($c->isInstalled() && !$c->isEnabled()){
					// But they do get sent to the disabled list!
					$this->_componentsDisabled[$n] = $c;

					unset($list[$n]);
					continue;
				}

				// Clear out the temporary class list
				$this->_tmpclasses = [];

				// If it's loaded, register it and remove it from the list!
				if ($c->isInstalled() && $c->isLoadable() && $c->loadFiles()) {

					try{
						// Allow for on-the-fly package upgrading regardless of DEV mode or not.
						if ($c->needsUpdated()) {

							// Load this component's classes in case an upgrade operation requires one.
							// This allows a component to be loaded partially without completely being loaded.
							$this->_tmpclasses = $c->getClassList();

							// Lock the site first!
							// This is because some upgrade procedures take a long time to upgrade.
							file_put_contents(TMP_DIR . 'lock.message', 'Core Plus is being upgraded, please try again in a minute. ');
							$c->upgrade();
							unlink(TMP_DIR . 'lock.message');
						}
					}
					catch(Exception $e){
						SystemLogModel::LogErrorEvent('/core/component/failedupgrade', 'Ignoring component [' . $n . '] due to an error during upgrading!', $e->getMessage());

						unlink(TMP_DIR . 'lock.message');
						//$c->disable();
						$this->_componentsDisabled[$n] = $c;
						unset($list[$n]);
						continue;
					}

					try{
						$this->_components[$n] = $c;
						$this->_registerComponent($c);
						$c->loadSupplementalModels();
					}
					catch(Exception $e){
						SystemLogModel::LogErrorEvent('/core/component/failedregister', 'Ignoring component [' . $n . '] due to an error during registration!', $e->getMessage());

						//$c->disable();
						$this->_componentsDisabled[$n] = $c;
						unset($list[$n]);
						continue;
					}

					unset($list[$n]);
					continue;
				}


				// Allow for on-the-fly package upgrading regardless of DEV mode or not.
				// Guess this is needed for the loadFiles part...
				if ($c->isInstalled() && $c->needsUpdated() && $c->isLoadable()) {
					// Lock the site first!
					// This is because some upgrade procedures take a long time to upgrade.
					file_put_contents(TMP_DIR . 'lock.message', 'Core Plus is being upgraded, please try again in a minute. ');

					$c->upgrade();
					$c->loadFiles();
					$this->_components[$n] = $c;
					$this->_registerComponent($c);
					unlink(TMP_DIR . 'lock.message');

					unset($list[$n]);
					continue;
				}

				// Allow packages to be auto-installed if in DEV mode.
				// If DEV mode is not enabled, just install the new component, do not enable it.
				if (!$c->isInstalled() && $c->isLoadable()) {
					// Load this component's classes in case an install operation requires one.
					// This allows a component to be loaded partially without completely being loaded.
					$this->_tmpclasses = $c->getClassList();

					// w00t
					$c->install();
					// BLAH, until I fix the disabled-packages-not-viewable bug...
					$c->enable();
					$c->loadFiles();
					$this->_components[$n] = $c;
					$this->_registerComponent($c);

					/*
					if(!DEVELOPMENT_MODE){
						$c->disable();
					}
					else{
						$c->enable();
						$c->loadFiles();
						$this->_components[$n] = $c;
						$this->_registerComponent($c);
					}
					*/
					unset($list[$n]);
					continue;
				}
			}
		}
		while ($size > 0 && ($size != sizeof($list)));

		// If dev mode is enabled, display a list of components installed but not loadable.

		foreach ($list as $n => $c) {

			//$this->_components[$n] = $c;
			$this->_componentsDisabled[$n] = $c;

			// Ignore anything with the execmode different, those should be minor notices for debugging if anything.
			if ($c->error & Component_2_1::ERROR_WRONGEXECMODE) continue;

			if (DEVELOPMENT_MODE) {
				SystemLogModel::LogErrorEvent('/core/component/missingrequirement', 'Could not load installed component ' . $n . ' due to requirement failed.', $c->getErrors());
			}
		}

		// Don't forget to load the themes too!
		if(class_exists('ThemeHandler')){
			foreach(ThemeHandler::GetAllThemes() as $theme){
				/** @var $theme Theme */
				$theme->load();
			}
		}

		// Lastly, make sure that the template path cache is updated!
		if(class_exists('\\Core\\Templates\\Template')){
			\Core\Templates\Template::RequeryPaths();	
		}
	}
コード例 #2
0
ファイル: Theme.php プロジェクト: nicholasryan/CorePlus
 /**
  * Copy in all the assets for this theme into the assets location.
  *
  * Returns false if nothing changed, else will return an array of all the changes that occured.
  *
  * @param bool $install   Set to false to uninstall the assets instead of installing.
  * @param int  $verbosity 0 for standard output, 1 for real-time, 2 for real-time verbose output.
  *
  * @return false | array
  * @throws \InstallerException
  */
 public function _parseAssets($install = true, $verbosity = 0)
 {
     $assetbase = \Core\Filestore\get_asset_path();
     $coretheme = \ConfigHandler::Get('/theme/selected');
     // WHY is core theme set to blank?!?
     // Damn installer...
     // this happens in the installer.
     if ($coretheme === null) {
         $coretheme = 'default';
     }
     $theme = $this->getKeyName();
     $changes = [];
     foreach ($this->_xmlloader->getElements('/assets/file') as $node) {
         // Cannot install assets if the directory is not setup!
         if (!$this->getAssetDir()) {
             continue;
         }
         $b = $this->getBaseDir();
         // The base filename with the directory.
         $filename = $node->getAttribute('filename');
         // The new theme asset will be installed into the same directory as its theme.
         // This differs from usual components because they just follow whatever theme is currently running.
         //$nf = Core::File($assetbase . $theme . '/' . $filename);
         $trimmedfilename = substr($b . $node->getAttribute('filename'), strlen($this->getAssetDir()));
         $themespecificfilename = $assetbase . $theme . '/' . $trimmedfilename;
         $newfilename = 'assets/' . $trimmedfilename;
         // Before anything, check and see if this file has a custom override file present.
         if (file_exists(ROOT_PDIR . 'themes/custom/' . $newfilename)) {
             // If so, then copy that asset to the custom directory too!
             $f = \Core\Filestore\Factory::File(ROOT_PDIR . 'themes/custom/' . $newfilename);
             $srcname = '!CUSTOM!';
         } else {
             // Otherwise, the local file is guaranteed to be a local file.
             $f = new \Core\Filestore\Backends\FileLocal($b . $filename);
             $srcname = '-theme- ';
         }
         if ($verbosity == 2) {
             CLI::PrintActionStart('Installing ' . $srcname . ' asset ' . $f->getBasename());
         }
         $nf = \Core\Filestore\Factory::File($newfilename);
         /*
         			// The various replacement possibilities for this file.
         			// The new destination must be in the theme-specific directory, this is a
         			// bit of a hack from the usual behaviour of the filestore system.
         			// Since that's designed to return the default if the theme-specific doesn't exist.
         			$replacements = array(
         				// The theme is not default, but the system translated the path to the default directory.
         				// This is because the file doesn't exist in any theme.
         				// This is actually expected behaviour, except unwanted here.
         				'default/' . $trimmedfilename => $theme . '/' . $trimmedfilename,
         				// The theme is not the currently installed, but the system translated the path to the that directory.
         				// This is because the filename is the same as the installed theme, so the system just translated there.
         				// We don't want that.
         				$coretheme . '/' . $trimmedfilename => $theme . '/' . $trimmedfilename,
         			);
         
         
         			foreach($replacements as $k => $v){
         				if($k == $v) continue;
         				if(strpos($nf->getFilename(), $k) !== false){
         					$nf->setFilename( str_replace($k, $v, $nf->getFilename()) );
         				}
         			}
         */
         // Check if this file even needs updated. (this is primarily used for reporting reasons)
         if ($nf->exists() && $nf->identicalTo($f)) {
             //echo "Skipping file, it's identical.<br/>";
             if ($verbosity == 2) {
                 CLI::PrintActionStatus('skip');
             }
             continue;
         } elseif ($nf->exists()) {
             $action = 'Replaced';
         } else {
             $action = 'Installed';
         }
         if (!$f->isReadable()) {
             throw new \InstallerException('Source file [' . $f->getFilename() . '] is not readable.');
         }
         try {
             $f->copyTo($nf, true);
         } catch (\Exception $e) {
             throw new \InstallerException('Unable to copy [' . $f->getFilename() . '] to [' . $nf->getFilename() . ']');
         }
         $change = $action . ' ' . $nf->getFilename();
         $changes[] = $change;
         if ($verbosity == 1) {
             CLI::PrintLine($change);
         } elseif ($verbosity == 2) {
             CLI::PrintActionStatus('ok');
         }
     }
     // If there are custom assets not registered by any application, install them too!
     // This will allow an admin to upload additional css resources and images easily.
     $directory = \Core\Filestore\Factory::Directory('themes/custom/assets');
     $ls = $directory->ls(null, true);
     $baseStrLen = strlen(ROOT_PDIR . '/themes/custom/assets');
     foreach ($ls as $fileOrDir) {
         if ($fileOrDir instanceof File) {
             $newfilename = substr($fileOrDir->getFilename(), $baseStrLen);
             if ($verbosity == 2) {
                 CLI::PrintActionStart('Installing CUSTOM   asset ' . $newfilename);
             }
             $nf = \Core\Filestore\Factory::File('asset/' . $newfilename);
             if ($nf->exists() && $nf->identicalTo($fileOrDir)) {
                 //echo "Skipping file, it's identical.<br/>";
                 if ($verbosity == 2) {
                     CLI::PrintActionStatus('skip');
                 }
                 continue;
             } elseif ($nf->exists()) {
                 $action = 'Replaced';
             } else {
                 $action = 'Installed';
             }
             try {
                 $fileOrDir->copyTo($nf, true);
             } catch (\Exception $e) {
                 throw new \InstallerException('Unable to copy [' . $fileOrDir->getFilename() . '] to [' . $nf->getFilename() . ']');
             }
             $change = $action . ' ' . $nf->getFilename();
             $changes[] = $change;
             if ($verbosity == 1) {
                 CLI::PrintLine($change);
             } elseif ($verbosity == 2) {
                 CLI::PrintActionStatus('ok');
             }
         }
     }
     if (!sizeof($changes)) {
         if ($verbosity > 0) {
             CLI::PrintLine('No changes required');
         }
         return false;
     }
     // Make sure the asset cache is purged!
     \Core\Cache::Delete('asset-resolveurl');
     return $changes;
 }
コード例 #3
0
	/**
	 * Component installation operations all share common actions, (mostly).
	 *
	 * Returns false if nothing changed, else will return an array containing all changes.
	 *
	 * @param int $verbosity 0 for standard output, 1 for real-time, 2 for real-time verbose output.
	 *
	 * @return false | array
	 * @throws InstallerException
	 */
	private function _performInstall($verbosity = 0) {
		// make sure that some of the installer elements are available!
		require_once(ROOT_PDIR . 'core/libs/core/InstallerException.php'); #SKIPCOMPILER

		$changed = array();

		$change = $this->_parseDBSchema(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseConfigs(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseUserConfigs(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parsePages(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseWidgets(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		$change = $this->_parseAssets(true, $verbosity);
		if ($change !== false){
			$changed = array_merge($changed, $change);
		}

		// Core has some additional things that need to ran through.
		if($this->getKeyName() == 'core'){
			// Make sure that files/private has a restrictive .htaccess file installed.
			$f = \Core\Filestore\Factory::File('private/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.private');
				if($src->copyTo($f)){
					$changed[] = 'Installed private htaccess file into ' . $f->getFilename();
				}
			}

			// Make sure that files/public has the appropriate .htaccess file installed.
			$f = \Core\Filestore\Factory::File('public/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.public');
				if($src->copyTo($f)){
					$changed[] = 'Installed public htaccess file into ' . $f->getFilename();
				}
			}

			// Make sure that files/public has the appropriate .htaccess file installed.
			$f = \Core\Filestore\Factory::File('asset/.htaccess');
			// This is a bit of a hack because I need the parent directory for assets, not the theme-specific version.
			$f->setFilename(dirname(dirname($f->getFilename())) . '/.htaccess');
			if(!$f->exists() && $f->isWritable()){
				$src = \Core\Filestore\Factory::File('core/htaccess.assets');
				if($src->copyTo($f)){
					$changed[] = 'Installed assets htaccess file into ' . $f->getFilename();
				}
			}
		}

		// Ensure that the core component cache is purged too!
		\Core\Cache::Delete('core-components');

		return (sizeof($changed)) ? $changed : false;
	}