Skip to content

Commit

Permalink
Merge branch 'release-0.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
zyxist committed Jun 12, 2011
2 parents 23e5ed9 + 3e701a1 commit 6f44438
Show file tree
Hide file tree
Showing 11 changed files with 470 additions and 4 deletions.
8 changes: 6 additions & 2 deletions README.md
@@ -1,4 +1,4 @@
Open Power Autoloader 3.0.1.0
Open Power Autoloader 3.0.2.0
=============================

This is a collection of universal class loaders for PHP 5.3+ compatible with
Expand All @@ -9,7 +9,7 @@ naming rules.
Version information
-------------------

This is a development version of Open Power Autoloader 3.0.1.0
This is a development version of Open Power Autoloader 3.0.2.0

Requirements
------------
Expand All @@ -33,8 +33,12 @@ The package provides the following class loaders:
Extra classes:

* `\Opl\Autoloader\ClassMapBuilder` - class map builder for the map-based autoloaders.
* `\Opl\Autoloader\CoreTracker` - an autoloader decorator that allows to find the common application
core loaded every time.
* `\Opl\Autoloader\Command\ClassMapBuild` - Symfony 2 Console command that builds
the class maps for the map-based autoloaders.
* `\Opl\Autoloader\Command\CoreDump` - Symfony 2 Console command that generates the
application core loading code from the `CoreTracker` dump.

Documentation can be found [here](http://static.invenzzia.org/docs/opl/3_0/book/en/autoloader.html).

Expand Down
2 changes: 1 addition & 1 deletion build.properties-dist
@@ -1,7 +1,7 @@
# Configure the project definitions here
project.name=Open Power Autoloader
project.filename=opl-autoloader
project.version=3.0.1.0
project.version=3.0.2.x
project.stability.release=devel
project.stability.api=devel
project.license=New BSD
Expand Down
2 changes: 2 additions & 0 deletions package.xml
Expand Up @@ -36,9 +36,11 @@ http://pear.php.net/dtd/package-2.0.xsd">
<contents>
<dir baseinstalldir="/" name="/">
<file baseinstalldir="/" name="Opl/Autoloader/Command/ClassMapBuild.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/Command/CoreDump.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/PHARLoader.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/ClassMapLoader.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/ClassMapBuilder.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/CoreTracker.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/GenericLoader.php" role="php" />
</dir>
</contents>
Expand Down
1 change: 1 addition & 0 deletions scripts/cli.php
Expand Up @@ -15,5 +15,6 @@

$cli->addCommands(array(
new \Opl\Autoloader\Command\ClassMapBuild(),
new \Opl\Autoloader\Command\CoreDump(),
));
$cli->run();
9 changes: 8 additions & 1 deletion src/Opl/Autoloader/ClassMapBuilder.php
Expand Up @@ -107,6 +107,13 @@ public function addNamespace($namespaceName, $path, $extension = '.php')
*/
protected function _processSingleFile($file)
{
// PHP 5.3 does not have this token, so we add it in order not to get
// warnings.
if(!defined('T_TRAIT'))
{
define('T_TRAIT', 65536);
}

$code = '';
$namespace = '';
$className = '';
Expand Down Expand Up @@ -135,7 +142,7 @@ protected function _processSingleFile($file)

$state = 1;
}
elseif($tokenName == T_CLASS || $tokenName == T_INTERFACE)
elseif($tokenName == T_CLASS || $tokenName == T_INTERFACE || $tokenName == T_TRAIT)
{
$state = 2;
}
Expand Down
134 changes: 134 additions & 0 deletions src/Opl/Autoloader/Command/CoreDump.php
@@ -0,0 +1,134 @@
<?php
/*
* OPEN POWER LIBS <http://www.invenzzia.org>
*
* This file is subject to the new BSD license that is bundled
* with this package in the file LICENSE. It is also available through
* WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
*
* Copyright (c) Invenzzia Group <http://www.invenzzia.org>
* and other contributors. See website for details.
*/
namespace Opl\Autoloader\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\Output;
use Symfony\Component\Console\Command\Command;

/**
* This command line interface command is responsible for building
* class maps for the ClassMapLoader.
*
* @author Tomasz Jędrzejewski
* @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
* @license http://www.invenzzia.org/license/new-bsd New BSD License
*/
class CoreDump extends Command
{
/**
* @see Command
*/
protected function configure()
{
$this->ignoreValidationErrors = true;

$this->setDefinition(array(
new InputArgument('definition', InputArgument::REQUIRED, 'The class location definition INI file'),
new InputArgument('core', InputArgument::OPTIONAL, 'The core file location, unless specified in the INI file.'),
))
->setName('opl:autoloader:core-dump-load')
->setDescription('Generates a list of require statements that load the common application core.')
->setHelp(<<<EOF
Use the <info>CoreTracker</info> autoloader decorator to find the common application
core by sending some HTTP requests. The more requests you perform, the more precise
the lookup is. The configuration for the command is given as
an INI file, where each entry represents a single top-level namespace and a path to its code:
[config]
coreDump = "./output/core.txt"
coreLoadOutput = "./application/core.php"
namespaceSeparator = "\\"
extension = ".php"
[namespaces]
Opl = "../libs/"
Foo = "../libs/"
Bar = "../other/"
It is recommended for the paths to have the trailing slashes prepended. The coreDump
value can be also provided as a command argument. The INI setting is ignored then.
EOF
);
} // end configure();

/**
* @see Command
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$definition = $input->getArgument('definition');
if(!$definition)
{
$output->writeln('<error>No definition file specified!</error>');
return;
}
$data = parse_ini_file($definition, true);
if(!is_array($data))
{
$output->writeln('<error>Invalid INI structure in the definition file!</error>');
return;
}

$coreDump = $input->getArgument('core');
if($coreDump)
{
$data['config']['coreDump'] = $coreDump;
}

if(!file_exists($data['config']['coreDump']))
{
$output->writeln('<error>Cannot open the core dump file!</error>');
return;
}
$dump = unserialize(file_get_contents($data['config']['coreDump']));
$outFile = fopen($data['config']['coreLoadOutput'], 'w');
fwrite($outFile, '<'.'?php'.PHP_EOL);

foreach($dump as $className)
{
$fileName = $this->toFilename($data['namespaces'], $data['config']['namespaceSeparator'], $className, $output);
if(false !== $fileName)
{
fwrite($outFile, 'require(\''.$fileName.$data['config']['extension'].'\');'.PHP_EOL);
}
}
fclose($outFile);
$output->writeln('<info>Core loading file generated.</info>');
} // end execute();

/**
* Returns the file name for the given class name.
*
* @param array $namespaces The list of available namespaces.
* @param string $className The class name to translate.
* @param OutputInterface $output The output interface.
*/
protected function toFilename(array $namespaces, $namespaceSeparator, $className, OutputInterface $output)
{
$className = ltrim($className, $namespaceSeparator);
$match = strstr($className, $namespaceSeparator, true);

if(false === $match || !isset($namespaces[$match]))
{
return false;
}
$rest = strrchr($className, $namespaceSeparator);
$replacement =
str_replace($namespaceSeparator, '/', substr($className, 0, strlen($className) - strlen($rest))).
str_replace(array('_', $namespaceSeparator), '/', $rest);

return $namespaces[$match].$replacement;
} // end toFilename();
} // end CoreDump;
150 changes: 150 additions & 0 deletions src/Opl/Autoloader/CoreTracker.php
@@ -0,0 +1,150 @@
<?php
/*
* OPEN POWER LIBS <http://www.invenzzia.org>
*
* This file is subject to the new BSD license that is bundled
* with this package in the file LICENSE. It is also available through
* WWW at this URL: <http://www.invenzzia.org/license/new-bsd>
*
* Copyright (c) Invenzzia Group <http://www.invenzzia.org>
* and other contributors. See website for details.
*/
namespace Opl\Autoloader;
use DomainException;

/**
* This decorator for any OPL autoloader tracks the loaded classes, attempting
* to find the common core of the entire application that must be always loaded.
* We can skip the autoloading procedure for it by generating a plain list of
* <tt>require</tt> commands.
*
* @author Tomasz Jędrzejewski
* @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
* @license http://www.invenzzia.org/license/new-bsd New BSD License
*/
class CoreTracker
{
/**
* The decorated autoloader.
* @var object
*/
protected $autoloader;
/**
* The core file name, where the results should be dumped.
* @var string
*/
protected $coreFileName;
/**
* The core file resource.
* @var resource
*/
protected $coreFile;
/**
* The current core layout.
* @var array
*/
protected $core;
/**
* The current scan.
* @var array
*/
protected $currentScan;
/**
* Whether we are generating the initial core or reducing the possibilities?
* @var integer
*/
protected $mode;

/**
* Creates the core tracker by decorating another autoloader.
*
* @param object $autoloader The decorated autoloader.
*/
public function __construct($autoloader, $coreFile)
{
if(!is_object($autoloader) || !method_exists($autoloader, 'loadClass'))
{
throw new DomainException('The first argument must be an autoloader object with \'loadClass\' method.');
}
$this->autoloader = $autoloader;
$this->coreFileName = (string)$coreFile;

if(!file_exists($this->coreFileName))
{
touch($this->coreFileName);
}
$this->coreFile = fopen($this->coreFileName, 'r+');

$content = '';
while(!feof($this->coreFile))
{
$content .= fread($this->coreFile, 2048);
}
rewind($this->coreFile);
$this->core = unserialize($content);
if(false == $this->core)
{
$this->core = array();
$this->mode = 0;
}
else
{
$this->mode = 1;
}
$this->currentScan = array();
} // end __construct();

/**
* Updates the core dump file.
*/
public function __destruct()
{
if(0 == $this->mode)
{
fwrite($this->coreFile, serialize($this->currentScan));
}
else
{
fwrite($this->coreFile, serialize(array_intersect($this->core, $this->currentScan)));
}
fclose($this->coreFile);
} // end __destruct();

/**
* Returns the decorated autoloader.
*
* @return object
*/
public function getAutoloader()
{
return $this->autoloader;
} // end getAutoloader();

/**
* Installs this class loader on the SPL autoload stack.
*/
public function register()
{
spl_autoload_register(array($this, 'loadClass'));
} // end register();

/**
* Uninstalls this class loader from the SPL autoloader stack.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
} // end unregister();

/**
* Performs the core tracking and delegates the loading to the decorated
* autoloader.
*/
public function loadClass($className)
{
// DO NOT CHANGE THE ORDER OR YOU'LL BREAK THE CLASS DEPENDENCIES!
$result = $this->autoloader->loadClass($className);
$this->currentScan[] = $className;
return $result;
} // end loadClass();
} // end CoreTracker;
1 change: 1 addition & 0 deletions tests/TestSuite/AllTests.php
Expand Up @@ -18,6 +18,7 @@ public static function suite()
$suite->addTestSuite('TestSuite\\GenericLoaderTest');
$suite->addTestSuite('TestSuite\\ClassMapLoaderTest');
$suite->addTestSuite('TestSuite\\PHARLoaderTest');
$suite->addTestSuite('TestSuite\\CoreTrackerTest');

return $suite;
} // end suite();
Expand Down

0 comments on commit 6f44438

Please sign in to comment.