<?php
/**
_Core_ClassLoader registers and defines the autoload method and methods for
retrieving Controllers public static properties from cache file and update
them if they change. It is a framework internal class instantiated by the _Core_FrontController
* @copyright Copyright (c) 2012, PWF
* @license http://phpwebframework.com/License
* @version PWF_0.3.0
*/
class _Core_ClassLoader
{
/**
* The directory of the cache files for Controllers static properties
*/
private static $cacheDir;
/**
* The unique id of the application
*/
public static $applicationId;
/**
* The reflections classes of the used Controllers in an array with the class name as key
*/
private static $reflectionClasses = array();
/**
* Array of the static properties of each Controller with the class name as key and an array
* with property name and each value, as value
*/
private $staticVariables = array();
/**
* The application properties object generated by the defined PROPERTIES_FILE of the index.php
* @var _Properties
*/
private $properties;
/**
* Three dimensions array with first key the class name , second key the static property
* name and third the flag "ID" for the special caching id and "VALUE" for the original
* value of the property after binding from caching file.
* @var array
*/
private static $cachingBinds;
/**
* Registers the autoload method
*/
public function __construct()
{
require_once(PWF_VERSION."/String.php");
spl_autoload_register(array($this, "load"));
}
/**
* Initiates the class for what is necessary for Controllers static properties caching
* and defines the External folder of the framework as include path (for classes outside
* PWF naming convensions).
* @param _Properties $properties
*/
public function init(_Properties $properties)
{
$pwfDir = _String::beforeLast(__FILE__, "Core");
set_include_path(get_include_path() . PATH_SEPARATOR . $pwfDir."External");
self::$cacheDir = $pwfDir."Cache";
self::$applicationId = hash("crc32",getcwd())."_"._String::afterLast(SRC, "/");
$this->properties = $properties;
}
/**
* The autoload method. It tries to load the classes whose name start from _ from the PWF_VERSION
* directory and all the others from the current src directory. Underscores are replaced with back
* slashes , and it adds the .php extension to the file to require. If the class name starts form
* Controller_ then it will try to load static properties from cache file.
* @param $className The class name to be loaded
* @throws _Exception_FileSystem
*/
public function load($className)
{
if(_String::startsWith($className, "_"))
{
require_once(PWF_VERSION._String::replace($className, "_", "/").".php");
}
else
{
$classFile = _String::replace($className, "_", "/").".php";
if(_File::exists($classFile))
{
require_once($classFile);
// Read static variables of controllerâs classes from cache files
if( _String::startsWith($className, $this->properties->get("CONTROLLERS_FOLDER")."_") )
{
$reflClass = new ReflectionClass($className);
if(!$reflClass->isInterface())
{
self::$reflectionClasses[$className] = $reflClass;
$file =self::$cacheDir."/".self::$applicationId."-".$className;
if(_File::exists($file))
{
$this->staticVariables[$className] = unserialize(_File::read($file));
foreach($this->staticVariables[$className] as $key=>$value)
{
self::$reflectionClasses[$className]->setStaticPropertyValue($key, $value);
}
}
}
}
}
else
{
if(isset($this->properties))
{
throw new _Exception_FileSystem($classFile." "._Exception_Messages::$fileNotFound, 4568);
}
}
}
}
/**
* It takes the name of a public static property (that is out of PWF caching
* static utility â it starts with _ ) and binds it with a PWF caching file
* depending on the given id. The first parameter is the class name where the
* property is declared.
* @param $className The name of the class
* @param $staticPropertyName The name of the static property
* @param $id The id that it will be used for that bind
*/
public static function cachingBind($className,$staticPropertyName,$id)
{
if(isset(self::$reflectionClasses[$className]) && _String::startsWith($staticPropertyName, "_") && self::$reflectionClasses[$className]->hasProperty($staticPropertyName))
{
$property = self::$reflectionClasses[$className]->getProperty($staticPropertyName);
if($property->isPublic() && $property->isStatic())
{
$file =self::$cacheDir."/".self::$applicationId."-".$className."-".$staticPropertyName."-".$id;
self::$cachingBinds[$className][$staticPropertyName]["ID"] = $id;
if(_File::exists($file))
{
$content = _File::read($file);
self::$cachingBinds[$className][$staticPropertyName]["VALUE"] = unserialize($content);
self::$reflectionClasses[$className]->setStaticPropertyValue($staticPropertyName, unserialize($content));
}
else
{
self::$cachingBinds[$className][$staticPropertyName]["VALUE"] = null;
self::$reflectionClasses[$className]->setStaticPropertyValue($staticPropertyName, null);
}
}
else
{
throw new _Exception_FlowControl(_String::prepare(_Exception_Messages::$staticPropertyBinfFailed,array($staticPropertyName,$className)), 1234);
}
}
else
{
throw new _Exception_FlowControl(_String::prepare(_Exception_Messages::$staticPropertyBinfFailed,array($staticPropertyName,$className)), 1234);
}
}
/**
* Checks if the static properties of used Controllers classes or
* the special caching static properties that have been binded have changed
* and if so it writes them in the class caching file
*/
public function cache()
{
foreach(self::$reflectionClasses as $className => $reflectionClass)
{
$newStatics = array();
$properties = $reflectionClass->getStaticProperties();
if(_Array::size($properties) > 0)
{
foreach($reflectionClass->getStaticProperties() as $key => $value)
{
$property = $reflectionClass->getProperty($key);
if($value != null && $property->getDeclaringClass()->getName() == $className && $property->isPublic() && !_String::startsWith($key, "_"))
{
$newStatics[$key] = $value;
}
}
}
if(count($newStatics) > 0)
{
$oldStatic = isset($this->staticVariables[$className]) ? $this->staticVariables[$className] : array();
if($oldStatic != $newStatics)
{
_File::write(self::$cacheDir."/".self::$applicationId."-".$className, serialize($newStatics));
}
}
if(isset(self::$cachingBinds[$className]))
{
foreach(self::$cachingBinds[$className] as $propertyName => $st)
{
$file =self::$cacheDir."/".self::$applicationId."-".$className."-".$propertyName."-".$st["ID"];
$newValue = $reflectionClass->getStaticPropertyValue($propertyName);
if($newValue == null && _File::exists($file))
{
_File::delete($file);
}
else if($newValue != $st["VALUE"])
{
_File::write($file, serialize($newValue));
}
}
}
}
}
}
?>