Skip to content
Browse files

Merge branch 'release-0.3'

  • Loading branch information...
2 parents 677dfd0 + dd39905 commit 5dd852091d429ed58e39d0a29cda50ad863bd4cc @zyxist zyxist committed
Showing with 3,127 additions and 276 deletions.
  1. +2 −1 .gitignore
  2. +20 −10 README.md
  3. +1 −1 build.properties-dist
  4. +2 −1 build.xml
  5. +22 −1 package.xml
  6. +202 −0 src/Opl/Autoloader/ApcLoader.php
  7. +197 −0 src/Opl/Autoloader/ChdbLoader.php
  8. +24 −48 src/Opl/Autoloader/ClassMapLoader.php
  9. +66 −62 src/Opl/Autoloader/Command/ClassMapBuild.php
  10. +53 −62 src/Opl/Autoloader/Command/CoreDump.php
  11. +2 −1 src/Opl/Autoloader/CoreTracker.php
  12. +26 −0 src/Opl/Autoloader/Exception/FileFormatException.php
  13. +26 −0 src/Opl/Autoloader/Exception/FileNotFoundException.php
  14. +28 −0 src/Opl/Autoloader/Exception/TranslationException.php
  15. +28 −28 src/Opl/Autoloader/GenericLoader.php
  16. +9 −4 src/Opl/Autoloader/PHARLoader.php
  17. +151 −0 src/Opl/Autoloader/Toolset/AbstractTool.php
  18. +27 −10 src/Opl/Autoloader/{ → Toolset}/ClassMapBuilder.php
  19. +282 −0 src/Opl/Autoloader/Toolset/Configuration.php
  20. +131 −0 src/Opl/Autoloader/Toolset/CoreDump.php
  21. +209 −0 src/Opl/Autoloader/UniversalLoader.php
  22. +11 −0 tests/Extra/DummyTool.php
  23. +7 −2 tests/TestSuite/AllTests.php
  24. +235 −0 tests/TestSuite/ApcLoaderTest.php
  25. +225 −0 tests/TestSuite/ChdbLoaderTest.php
  26. +40 −6 tests/TestSuite/ClassMapLoaderTest.php
  27. +7 −0 tests/TestSuite/CoreTrackerTest.php
  28. +42 −0 tests/TestSuite/ExceptionTest.php
  29. +24 −9 tests/TestSuite/GenericLoaderTest.php
  30. +25 −5 tests/TestSuite/PHARLoaderTest.php
  31. +178 −0 tests/TestSuite/Toolset/AbstractToolTest.php
  32. +24 −0 tests/TestSuite/Toolset/AllTests.php
  33. +15 −11 tests/TestSuite/{ → Toolset}/ClassMapBuilderTest.php
  34. +150 −0 tests/TestSuite/Toolset/ConfigurationTest.php
  35. +75 −0 tests/TestSuite/Toolset/CoreDumpTest.php
  36. +311 −0 tests/TestSuite/UniversalLoaderTest.php
  37. +2 −0 tests/bootstrap.dist.php
  38. +1 −0 tests/coverage.xml
  39. +0 −12 tests/data/classMap.ini
  40. +1 −1 tests/data/classMap.txt
  41. +13 −0 tests/data/config.xml
  42. +34 −0 tests/data/configs/correctConfig.xml
  43. +5 −0 tests/data/configs/invalidFile.xml
  44. +6 −0 tests/data/configs/missingFileAttribute.xml
  45. +19 −0 tests/data/configs/missingNamespaceAttribute.xml
  46. +19 −0 tests/data/configs/missingSeparatorAttribute.xml
  47. +19 −0 tests/data/configs/noHeadings.xml
  48. +33 −0 tests/data/configs/simpleConfig.xml
  49. +1 −0 tests/data/core.txt
  50. +1 −0 tests/data/invalid_map.txt
  51. +30 −0 tests/data/outputs/testExportConcatenatedCanRemoveHeadingComments.php
  52. +43 −0 tests/data/outputs/testExportConcatenatedConcatenatesTheFiles.php
  53. +7 −0 tests/data/outputs/testExportRequireListProducesRequireList.php
  54. +2 −1 tests/no-coverage.xml
  55. +14 −0 tests/produce-core.php
View
3 .gitignore
@@ -7,5 +7,6 @@ build.properties
tests/cache/*
tests/coverage/*
tests/bootstrap.php
+tests/data/classMap.chdb
catalog.xml
-nbproject/*
+nbproject/*
View
30 README.md
@@ -1,4 +1,4 @@
-Open Power Autoloader 3.0.2.0
+Open Power Autoloader 3.0.3.0
=============================
This is a collection of universal class loaders for PHP 5.3+ compatible with
@@ -9,14 +9,15 @@ naming rules.
Version information
-------------------
-This is a development version of Open Power Autoloader 3.0.2.0
+This is a development version of Open Power Autoloader 3.0.3.0
Requirements
------------
-+ PHP 5.3+
-+ [Open Power Cache](http://www.github.com/OPL/opl3-cache) (Optional)
-+ [Symfony 2 Console Component](http://www.symfony-reloaded.org) (Optional)
++ PHP 5.3 or 5.4
++ [Symfony 2 Console Component](http://www.symfony-reloaded.org) (Optional, recommended)
++ [Advanced PHP Cache](http://pecl.php.net/package/APC) (Optional)
++ [chdb](http://pecl.php.net/package/chdb) (Optional)
Contents
--------
@@ -25,20 +26,29 @@ The package provides the following class loaders:
* `\Opl\Autoloader\GenericLoader` - generic class loader with dynamic class-to-file
translation.
+* `\Opl\Autoloader\UniversalLoader` - a slower variant of `GenericLoader` that allows
+ to register subnamespaces, too.
* `\Opl\Autoloader\ClassMapLoader` - class loader which uses a predefined map of
classes and their paths. Provides greater performance at the cost of flexibility.
* `\Opl\Autoloader\PHARLoader` - class loader with predefined maps of classes for
self-contained PHAR archives with web and console applications.
+* `\Opl\Autoloader\ApcLoader` - a modification of `ClassMapLoader` which allows to
+ cache the class maps in the [APC](http://pecl.php.net/package/APC) shared memory.
+* `\Opl\Autoloader\ChdbLoader` - a modification of `ClassMapLoader` which uses Unix
+ shared memory files and [chdb](http://pecl.php.net/package/chdb) caching extension
+ to store the class maps.
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.
+
+Extra tools:
+
+* *Class map builder* - produces the class maps for the given namespaces in the serialized
+ array or chdb shared memory file formats.
+* *CoreDump* - exports the core dump generated by the `CoreTracker`, concatenating it
+ into a single PHP file or a list of *require* statements.
Documentation can be found [here](http://static.invenzzia.org/docs/opl/3_0/book/en/autoloader.html).
View
2 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.2.x
+project.version=3.0.3.x
project.stability.release=devel
project.stability.api=devel
project.license=New BSD
View
3 build.xml
@@ -24,7 +24,7 @@
<echo msg="Making the build directories" />
<mkdir dir="${project.directory.build}" />
<mkdir dir="${project.directory.output}" />
- </target>
+ </target>
<!-- builds the application in order to be released -->
<target name="build" depends="prepare">
@@ -41,6 +41,7 @@
<exclude name="bootstrap.php" />
<exclude name="cache/**" />
<exclude name="coverage/**" />
+ <exclude name="data/classMap.chdb" />
</fileset>
</copy>
<copy file="LICENSE" tofile="${project.directory.build}/LICENSE" overwrite="true"/>
View
23 package.xml
@@ -37,11 +37,20 @@ http://pear.php.net/dtd/package-2.0.xsd">
<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/Exception/FileFormatException.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Exception/FileNotFoundException.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Exception/TranslationException.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Toolset/AbstractTool.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Toolset/ClassMapBuilder.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Toolset/Configuration.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/Toolset/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/ApcLoader.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/ChdbLoader.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/CoreTracker.php" role="php" />
<file baseinstalldir="/" name="Opl/Autoloader/GenericLoader.php" role="php" />
+ <file baseinstalldir="/" name="Opl/Autoloader/UniversalLoader.php" role="php" />
</dir>
</contents>
@@ -50,6 +59,18 @@ http://pear.php.net/dtd/package-2.0.xsd">
<php><min>5.3.0</min></php>
<pearinstaller><min>1.4.0</min></pearinstaller>
</required>
+ <optional>
+ <package>
+ <name>Console</name>
+ <channel>pear.symfony.com</channel>
+ </package>
+ <extension>
+ <name>APC</name>
+ </extension>
+ <extension>
+ <name>chdb</name>
+ </extension>
+ </optional>
</dependencies>
<phprelease>
View
202 src/Opl/Autoloader/ApcLoader.php
@@ -0,0 +1,202 @@
+<?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;
+use RuntimeException;
+
+/**
+ * A modification of the <tt>ClassMapLoader</tt> which allows to use
+ * Advanced PHP Cache to store the class map instead of loading it
+ * from a file.
+ *
+ * @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 ApcLoader
+{
+ /**
+ * The default autoloader path.
+ * @var string
+ */
+ private $defaultPath = '';
+
+ /**
+ * The list of available top-level namespaces.
+ * @var array
+ */
+ private $namespaces = array();
+ /**
+ * The loaded class map.
+ * @var array
+ * @internal
+ */
+ protected $classMap;
+
+ /**
+ * The location where the class map is stored.
+ * @var string
+ * @internal
+ */
+ protected $classMapLocation;
+
+ /**
+ * Creates the class map loader and loads the map into the memory.
+ * The map must be constructed with the command line interface.
+ *
+ * @param string $defaultPath The default location path used for newly registered namespaces
+ * @param string $classMapLocation The class map location on the disk
+ * @param string @apcKey The APC cache key
+ */
+ public function __construct($defaultPath, $classMapLocation, $apcKey)
+ {
+ $this->setDefaultPath($defaultPath);
+ $this->classMapLocation = $classMapLocation;
+
+ $this->classMap = apc_fetch($apcKey);
+ if(!is_array($this->classMap))
+ {
+ if(!file_exists($this->classMapLocation))
+ {
+ throw new RuntimeException('Cannot find a class map under the specified location.');
+ }
+ $this->classMap = @unserialize(file_get_contents($this->classMapLocation));
+ if(!is_array($this->classMap))
+ {
+ throw new RuntimeException('The loaded file does not contain a valid class map.');
+ }
+ apc_store($apcKey, $this->classMap);
+ }
+ } // end __construct();
+
+ /**
+ * Registers a new top-level namespace to match. If no path is specified, the current
+ * default path is taken.
+ *
+ * @throws RuntimeException
+ * @param string $namespace The namespace name to add.
+ * @param string $path The path to the namespace.
+ */
+ public function addNamespace($namespace, $path = null)
+ {
+ if(isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is already added.');
+ }
+ if($path !== null)
+ {
+ $length = strlen($path);
+ if($length == 0 || $path[$length - 1] != '/')
+ {
+ $path .= '/';
+ }
+ $this->namespaces[(string)$namespace] = $path;
+ }
+ else
+ {
+ $this->namespaces[(string)$namespace] = $this->defaultPath;
+ }
+ } // end addNamespace();
+
+ /**
+ * Checks if the specified namespace is available.
+ *
+ * @param string $namespace The namespace name to check.
+ */
+ public function hasNamespace($namespace)
+ {
+ return isset($this->namespaces[(string)$namespace]);
+ } // end hasNamespace();
+
+ /**
+ * Removes a registered top-level namespace.
+ *
+ * @throws RuntimeException
+ * @param string $namespace The namespace name to remove.
+ */
+ public function removeNamespace($namespace)
+ {
+ if(!isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is not available.');
+ }
+ unset($this->namespaces[(string)$namespace]);
+ } // end removeNamespace();
+
+ /**
+ * Sets the default path used by the namespaces. Note that it does not affect
+ * the already added namespaces.
+ *
+ * @param string $defaultPath The new default path.
+ */
+ public function setDefaultPath($defaultPath)
+ {
+ $length = strlen($defaultPath);
+ if($length == 0 || $defaultPath[$length - 1] != '/')
+ {
+ $defaultPath .= '/';
+ }
+ $this->defaultPath = $defaultPath;
+ } // end setDefaultPath();
+
+ /**
+ * Returns the default path used by the namespaces.
+ *
+ * @return string The current default path.
+ */
+ public function getDefaultPath()
+ {
+ return $this->defaultPath;
+ } // end getDefaultPath();
+
+ /**
+ * Returns the current class map location.
+ *
+ * @return string
+ */
+ public function getClassMapLocation()
+ {
+ return $this->classMapLocation;
+ } // end getClassMapLocation();
+
+ /**
+ * 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();
+
+ /**
+ * Attempts to load the specified class from a file.
+ *
+ * @param string $className The class name.
+ * @return boolean
+ */
+ public function loadClass($className)
+ {
+ if(!isset($this->classMap[$className]))
+ {
+ return false;
+ }
+ require($this->namespaces[$this->classMap[$className][0]].$this->classMap[$className][1]);
+ return true;
+ } // end loadClass();
+} // end ApcLoader;
View
197 src/Opl/Autoloader/ChdbLoader.php
@@ -0,0 +1,197 @@
+<?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 chdb;
+use DomainException;
+use Exception;
+use RuntimeException;
+
+/**
+ * A modification of the <tt>ClassMapLoader</tt> which allows to use
+ * the <tt>chdb</tt> (http://pecl.php.net/package/chdb) caching extension
+ * to store the class maps.
+ *
+ * @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 ChdbLoader
+{
+ /**
+ * The default autoloader path.
+ * @var string
+ */
+ private $defaultPath = '';
+
+ /**
+ * The list of available top-level namespaces.
+ * @var array
+ */
+ private $namespaces = array();
+ /**
+ * The loaded class map.
+ * @var array
+ * @internal
+ */
+ protected $classMap;
+ /**
+ * The location where the class map is stored.
+ * @var string
+ * @internal
+ */
+ protected $classMapLocation;
+
+ /**
+ * Creates the class map loader and loads the map into the memory.
+ * The map must be constructed with the command line interface.
+ *
+ * @param string $defaultPath The default location path used for newly registered namespaces
+ * @param string $classMapLocation The chdb mapped memory file with the class map.
+ */
+ public function __construct($defaultPath, $classMapLocation)
+ {
+ $this->setDefaultPath($defaultPath);
+ $this->classMapLocation = $classMapLocation;
+ try
+ {
+ $this->classMap = new chdb($this->classMapLocation);
+ }
+ catch(Exception $exception)
+ {
+ throw new RuntimeException('Cannot find a class map under the specified location.');
+ }
+ } // end __construct();
+
+ /**
+ * Registers a new top-level namespace to match. If no path is specified, the current
+ * default path is taken.
+ *
+ * @throws RuntimeException
+ * @param string $namespace The namespace name to add.
+ * @param string $path The path to the namespace.
+ */
+ public function addNamespace($namespace, $path = null)
+ {
+ if(isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is already added.');
+ }
+ if($path !== null)
+ {
+ $length = strlen($path);
+ if($length == 0 || $path[$length - 1] != '/')
+ {
+ $path .= '/';
+ }
+ $this->namespaces[(string)$namespace] = $path;
+ }
+ else
+ {
+ $this->namespaces[(string)$namespace] = $this->defaultPath;
+ }
+ } // end addNamespace();
+
+ /**
+ * Checks if the specified namespace is available.
+ *
+ * @param string $namespace The namespace name to check.
+ */
+ public function hasNamespace($namespace)
+ {
+ return isset($this->namespaces[(string)$namespace]);
+ } // end hasNamespace();
+
+ /**
+ * Removes a registered top-level namespace.
+ *
+ * @throws RuntimeException
+ * @param string $namespace The namespace name to remove.
+ */
+ public function removeNamespace($namespace)
+ {
+ if(!isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is not available.');
+ }
+ unset($this->namespaces[(string)$namespace]);
+ } // end removeNamespace();
+
+ /**
+ * Sets the default path used by the namespaces. Note that it does not affect
+ * the already added namespaces.
+ *
+ * @param string $defaultPath The new default path.
+ */
+ public function setDefaultPath($defaultPath)
+ {
+ $length = strlen($defaultPath);
+ if($length == 0 || $defaultPath[$length - 1] != '/')
+ {
+ $defaultPath .= '/';
+ }
+ $this->defaultPath = $defaultPath;
+ } // end setDefaultPath();
+
+ /**
+ * Returns the default path used by the namespaces.
+ *
+ * @return string The current default path.
+ */
+ public function getDefaultPath()
+ {
+ return $this->defaultPath;
+ } // end getDefaultPath();
+
+ /**
+ * Returns the current class map location.
+ *
+ * @return string
+ */
+ public function getClassMapLocation()
+ {
+ return $this->classMapLocation;
+ } // end getClassMapLocation();
+
+ /**
+ * 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();
+
+ /**
+ * Attempts to load the specified class from a file.
+ *
+ * @param string $className The class name.
+ * @return boolean
+ */
+ public function loadClass($className)
+ {
+ $class = $this->classMap->get($className);
+ if(null === $class)
+ {
+ return false;
+ }
+ $class = unserialize($class);
+ require($this->namespaces[$class[0]].$class[1]);
+ return true;
+ } // end loadClass();
+} // end ChdbLoader;
View
72 src/Opl/Autoloader/ClassMapLoader.php
@@ -10,8 +10,8 @@
* and other contributors. See website for details.
*/
namespace Opl\Autoloader;
+use DomainException;
use RuntimeException;
-use Opl\Cache\Cache;
/**
* This autoloader is based on the pre-computed class location
@@ -29,26 +29,26 @@ class ClassMapLoader
* @static
* @var string
*/
- private $_defaultPath = '';
+ private $defaultPath = '';
/**
* The list of available top-level namespaces.
* @var array
*/
- private $_namespaces = array();
+ private $namespaces = array();
/**
* The loaded class map.
* @var array
* @internal
*/
- protected $_classMap;
+ protected $classMap;
/**
* The location where the class map is stored.
* @var string
* @internal
*/
- protected $_classMapLocation;
+ protected $classMapLocation;
/**
* Creates the class map loader and loads the map into the memory.
@@ -56,47 +56,23 @@ class ClassMapLoader
*
* @param string $defaultPath The default location path used for newly registered namespaces
* @param string $classMapLocation The class map location on the disk
- * @param Cache $cache The optional memory cache to be used
*/
- public function __construct($defaultPath, $classMapLocation, Cache $cache = null)
+ public function __construct($defaultPath, $classMapLocation)
{
$this->setDefaultPath($defaultPath);
- $this->_classMapLocation = $classMapLocation;
+ $this->classMapLocation = $classMapLocation;
- if(null !== $cache)
- {
- $this->_classMap = $cache->get('classMap');
- if(null === $this->_classMap)
- {
- $this->_loadMap();
- $cache->set('classMap', $this->_classMap);
- }
- }
- else
- {
- $this->_loadMap();
- }
- } // end __construct();
-
- /**
- * Loads the map from a file.
- *
- * @internal
- * @throws RuntimeException
- */
- protected function _loadMap()
- {
- if(!file_exists($this->_classMapLocation))
+ if(!file_exists($this->classMapLocation))
{
throw new RuntimeException('Cannot find a class map under the specified location.');
}
- $this->_classMap = unserialize(file_get_contents($this->_classMapLocation));
+ $this->classMap = @unserialize(file_get_contents($this->classMapLocation));
- if(!is_array($this->_classMap))
+ if(!is_array($this->classMap))
{
throw new RuntimeException('The loaded file does not contain a valid class map.');
}
- } // end _loadMap();
+ } // end __construct();
/**
* Registers a new top-level namespace to match. If no path is specified, the current
@@ -108,9 +84,9 @@ protected function _loadMap()
*/
public function addNamespace($namespace, $path = null)
{
- if(isset($this->_namespaces[(string)$namespace]))
+ if(isset($this->namespaces[(string)$namespace]))
{
- throw new RuntimeException('The namespace '.$namespace.' is already added.');
+ throw new DomainException('The namespace '.$namespace.' is already added.');
}
if($path !== null)
{
@@ -119,11 +95,11 @@ public function addNamespace($namespace, $path = null)
{
$path .= '/';
}
- $this->_namespaces[(string)$namespace] = $path;
+ $this->namespaces[(string)$namespace] = $path;
}
else
{
- $this->_namespaces[(string)$namespace] = $this->_defaultPath;
+ $this->namespaces[(string)$namespace] = $this->defaultPath;
}
} // end addNamespace();
@@ -134,7 +110,7 @@ public function addNamespace($namespace, $path = null)
*/
public function hasNamespace($namespace)
{
- return isset($this->_namespaces[(string)$namespace]);
+ return isset($this->namespaces[(string)$namespace]);
} // end hasNamespace();
/**
@@ -145,11 +121,11 @@ public function hasNamespace($namespace)
*/
public function removeNamespace($namespace)
{
- if(!isset($this->_namespaces[(string)$namespace]))
+ if(!isset($this->namespaces[(string)$namespace]))
{
- throw new RuntimeException('The namespace '.$namespace.' is not available.');
+ throw new DomainException('The namespace '.$namespace.' is not available.');
}
- unset($this->_namespaces[(string)$namespace]);
+ unset($this->namespaces[(string)$namespace]);
} // end removeNamespace();
/**
@@ -165,7 +141,7 @@ public function setDefaultPath($defaultPath)
{
$defaultPath .= '/';
}
- $this->_defaultPath = $defaultPath;
+ $this->defaultPath = $defaultPath;
} // end setDefaultPath();
/**
@@ -175,7 +151,7 @@ public function setDefaultPath($defaultPath)
*/
public function getDefaultPath()
{
- return $this->_defaultPath;
+ return $this->defaultPath;
} // end getDefaultPath();
/**
@@ -185,7 +161,7 @@ public function getDefaultPath()
*/
public function getClassMapLocation()
{
- return $this->_classMapLocation;
+ return $this->classMapLocation;
} // end getClassMapLocation();
/**
@@ -212,11 +188,11 @@ public function unregister()
*/
public function loadClass($className)
{
- if(!isset($this->_classMap[$className]))
+ if(!isset($this->classMap[$className]))
{
return false;
}
- require($this->_namespaces[$this->_classMap[$className][0]].$this->_classMap[$className][1]);
+ require($this->namespaces[$this->classMap[$className][0]].$this->classMap[$className][1]);
return true;
} // end loadClass();
} // end ClassMapLoader;
View
128 src/Opl/Autoloader/Command/ClassMapBuild.php
@@ -10,13 +10,15 @@
* and other contributors. See website for details.
*/
namespace Opl\Autoloader\Command;
-use Opl\Autoloader\ClassMapBuilder;
+use Opl\Autoloader\Toolset\ClassMapBuilder;
+use Opl\Autoloader\Toolset\Configuration;
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;
+use RuntimeException;
/**
* This command line interface command is responsible for building
@@ -29,12 +31,6 @@
class ClassMapBuild extends Command
{
/**
- * The class map builder.
- * @var ClassMapBuilder
- */
- protected $_builder;
-
- /**
* @see Command
*/
protected function configure()
@@ -42,25 +38,18 @@ protected function configure()
$this->ignoreValidationErrors = true;
$this->setDefinition(array(
- new InputArgument('definition', InputArgument::REQUIRED, 'The class map definition INI file'),
+ new InputArgument('configuration', InputArgument::REQUIRED, 'The Open Power Autoloader configuration'),
))
+ ->addOption('type', 't', InputOption::VALUE_REQUIRED, 'Map type: \'serialized\' or \'chdb\'')
->setName('opl:autoloader:build-class-map')
->setDescription('Generates the class map for the ClassMapLoader')
->setHelp(<<<EOF
The <info>autoloader:class-map:build</info> command is responsible for building
-the class maps for the ClassMapLoader autoloader. The configuration is given as
-an INI file, where each entry represents a single top-level namespace and a path to its code:
-
- [config]
- outputFile = "./data/classMap.txt"
- extension = "./php"
-
- [namespaces]
- Opl = "../libs/"
- Foo = "../libs/"
- Bar = "../other/"
+the class maps for the ClassMapLoader autoloader. The configuration file is an
+XML document. Please refer to the OPA user manual to get to know more.
-It is recommended for the paths to have the trailing slashes prepended.
+The extra option \'type\' defines the output format: either a serialized array or
+a memory-mapped file for \'chdb\' PECL extension (Unix only).
EOF
);
} // end configure();
@@ -70,64 +59,79 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $definition = $input->getArgument('definition');
- if(!$definition)
+ try
{
- $output->writeln('<error>No definition file specified!</error>');
+ $configuration = new Configuration($input->getArgument('configuration'));
+ }
+ catch(RuntimeException $exception)
+ {
+ $output->writeln('<error>An error occured: '.$exception->getMessage().'</error>');
return;
}
-
- if(!file_exists($definition))
+
+ $type = $input->getOption('type');
+ if(empty($type))
{
- $output->writeln('<error>The specified definition file does not exist!</error>');
+ $type = 'serialized';
}
- $data = parse_ini_file($definition, true);
- if(!is_array($data))
+ if($type != 'serialized' && $type != 'chdb')
{
- $output->writeln('<error>Invalid INI structure in the definition file!</error>');
+ $output->writeln('<error>Invalid type specified.</error>');
+ return;
+ }
+ switch($type)
+ {
+ case 'serialized':
+ $optionName = 'serialized-class-map';
+ break;
+ case 'chdb':
+ if(!extension_loaded('chdb'))
+ {
+ $output->writeln('<error>chdb extension is not installed.</error>');
+ return;
+ }
+ $optionName = 'chdb-class-map';
+ }
+
+ if(!$configuration->hasFile($optionName))
+ {
+ $output->writeln('<error>The class map file definition is missing in the configuration file!</error>');
+ $output->writeln('Hint: add \''.$optionName.'\' file type to export-files section.');
+ return;
}
- $extension = 'php';
- $outputFile = './class-map.txt';
- if(isset($data['config']))
+ $builder = new ClassMapBuilder();
+
+ foreach($configuration->getSeparators() as $separator)
{
- if(isset($data['config']['extension']))
- {
- $extension = $data['config']['extension'];
- }
- if(isset($data['config']['outputFile']))
+ foreach($configuration->getSeparatorNamespaces($separator) as $name => $namespace)
{
- $outputFile = $data['config']['outputFile'];
+ $builder->addNamespace($name, $namespace['path'], $namespace['extension']);
}
}
-
- if(!isset($data['namespaces']))
+ $errors = $builder->buildMap();
+ foreach($errors as $error)
{
- $output->writeln('<error>No namespaces specified!</error>');
+ $output->writeln(preg_replace('/^(([^\:]+)\:) (.*)$/', '<error>Warning: $1</error> $3', $error));
}
-
- $this->_builder = new ClassMapBuilder();
- foreach($data['namespaces'] as $name => $path)
+
+ if($type == 'serialized')
{
- $this->_processSingleNamespace($output, $name, $path, $extension);
+ file_put_contents($configuration->getFile($optionName), serialize($builder->getMap()));
}
- file_put_contents($outputFile, serialize($this->_builder->getMap()));
- $output->writeln('<info>Map saved as:</info> '.$outputFile);
- } // end execute();
-
- /**
- * Processes a single top-level namespace.
- *
- * @param string $name
- * @param string $path
- */
- protected function _processSingleNamespace(OutputInterface $output, $namespaceName, $path, $extension)
- {
- $errors = $this->_builder->addNamespace($namespaceName, $path, $extension);
-
- foreach($errors as $error)
+ else
{
- $output->writeln(preg_replace('/^(([^\:]+)\:) (.*)$/', '<error>$1</error> $3', $error));
+ $fileName = $configuration->getFile($optionName);
+
+ $map = array();
+ foreach($builder->getMap() as $className => $data)
+ {
+ $map[$className] = serialize($data);
+ }
+
+ chdb_create($fileName.'.0', $map);
+ rename($fileName.'.0', $fileName);
}
- } // end _processSingleNamespace();
+ $output->writeln('<info>Map saved as:</info> '.$configuration->getFile($optionName));
+ } // end execute();
} // end ClassMapBuild;
View
115 src/Opl/Autoloader/Command/CoreDump.php
@@ -10,6 +10,8 @@
* and other contributors. See website for details.
*/
namespace Opl\Autoloader\Command;
+use Opl\Autoloader\Toolset\Configuration;
+use Opl\Autoloader\Toolset\CoreDump as CoreDumpTool;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputInterface;
@@ -35,30 +37,24 @@ 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.'),
+ new InputArgument('configuration', InputArgument::REQUIRED, 'The OPA configuration file.'),
))
- ->setName('opl:autoloader:core-dump-load')
+ ->addOption('core', 'c', InputOption::VALUE_REQUIRED, 'The path to the core file.')
+ ->addOption('export-type', 'e', InputOption::VALUE_REQUIRED, 'Export type: \'require\' or \'concat\'')
+ ->addOption('strip-comments', 's', InputOption::VALUE_NONE, 'Strip comment headers in the concatenated files.')
+ ->setName('opl:autoloader:core-dump-export')
->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:
+the lookup is. The command requires the path to the Open Power Autoloader XML configuration
+file to be passed. Please refer to the library manual to read more about it.
- [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.
+The default export type is \'require\' which generates a list of \'require\' statements
+that load the core files. Another supported type is \'concat\' which concatenates the
+core files into a single PHP file. Use it with -s option to strip the header comments
+from the concatenated files. The concatenation is safe both for namespaces and non-namespaced
+code.
EOF
);
} // end configure();
@@ -68,67 +64,62 @@ protected function configure()
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
- $definition = $input->getArgument('definition');
- if(!$definition)
+ try
+ {
+ $configuration = new Configuration($input->getArgument('configuration'));
+ }
+ catch(RuntimeException $exception)
{
- $output->writeln('<error>No definition file specified!</error>');
+ $output->writeln('<error>An error occured: '.$exception->getMessage().'</error>');
return;
}
- $data = parse_ini_file($definition, true);
- if(!is_array($data))
+
+ $core = $input->getOption('core');
+ if(!$configuration->hasFile('core-dump') && empty($core))
{
- $output->writeln('<error>Invalid INI structure in the definition file!</error>');
+ $output->writeln('<error>The path to the core dump file is missing.</error>');
+ $output->writeln('Hint: add \'core-dump\' file type to export-files section or use the --core option.');
return;
}
-
- $coreDump = $input->getArgument('core');
- if($coreDump)
+ elseif(empty($core))
{
- $data['config']['coreDump'] = $coreDump;
+ $core = $configuration->getFile('core-dump');
}
-
- if(!file_exists($data['config']['coreDump']))
+ if(!$configuration->hasFile('core-export'))
{
- $output->writeln('<error>Cannot open the core dump file!</error>');
+ $output->writeln('<error>The path to the core export file is missing.</error>');
+ $output->writeln('Hint: add \'core-export\' file type to export-files section.');
+ return;
+ }
+ $exportType = $input->getOption('export-type');
+ if(empty($exportType))
+ {
+ $exportType = 'require';
+ }
+ elseif($exportType != 'require' && $exportType != 'concat')
+ {
+ $output->writeln('<error>Invalid value for the --export-type option: \'require\' or \'concat\' expected.</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)
+ $dump = new CoreDumpTool();
+ foreach($configuration->getSeparators() as $separator)
{
- $fileName = $this->toFilename($data['namespaces'], $data['config']['namespaceSeparator'], $className, $output);
- if(false !== $fileName)
+ foreach($configuration->getSeparatorNamespaces($separator) as $name => $namespace)
{
- fwrite($outFile, 'require(\''.$fileName.$data['config']['extension'].'\');'.PHP_EOL);
+ $dump->addNamespace($name, $namespace['path'], $namespace['extension']);
}
}
- 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]))
+ $dump->loadCore($core);
+ if($exportType == 'require')
{
- return false;
+ $dump->exportRequireList($configuration->getFile('core-export'));
+ }
+ else
+ {
+ $dump->exportConcatenated($configuration->getFile('core-export'), $input->getOption('strip-comments') ? true : 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();
+ $output->writeln('<info>The core loader has been successfully exported.</info>');
+ } // end execute();
} // end CoreDump;
View
3 src/Opl/Autoloader/CoreTracker.php
@@ -80,8 +80,9 @@ public function __construct($autoloader, $coreFile)
{
$content .= fread($this->coreFile, 2048);
}
+ ftruncate($this->coreFile, 0);
rewind($this->coreFile);
- $this->core = unserialize($content);
+ $this->core = @unserialize($content);
if(false == $this->core)
{
$this->core = array();
View
26 src/Opl/Autoloader/Exception/FileFormatException.php
@@ -0,0 +1,26 @@
+<?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\Exception;
+use RuntimeException;
+
+/**
+ * This exception is thrown by the configuration parser, if the configuration
+ * file cannot be read.
+ *
+ * @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 FileFormatException extends RuntimeException
+{
+
+} // end FileFormatException;
View
26 src/Opl/Autoloader/Exception/FileNotFoundException.php
@@ -0,0 +1,26 @@
+<?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\Exception;
+use RuntimeException;
+
+/**
+ * This exception is used by the toolset classes to report that they cannot
+ * find a requested file.
+ *
+ * @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 FileNotFoundException extends RuntimeException
+{
+
+} // end FileNotFoundException;
View
28 src/Opl/Autoloader/Exception/TranslationException.php
@@ -0,0 +1,28 @@
+<?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\Exception;
+use RuntimeException;
+
+/**
+ * The exception allows to report class-to-filename translation problems.
+ * It is used in the toolset. The autoloaders are not allowed to throw
+ * sophisticated exceptions, as they are not a part of the application, but
+ * the runtime environment.
+ *
+ * @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 TranslationException extends RuntimeException
+{
+
+} // end TranslationException;
View
56 src/Opl/Autoloader/GenericLoader.php
@@ -10,7 +10,7 @@
* and other contributors. See website for details.
*/
namespace Opl\Autoloader;
-use RuntimeException;
+use DomainException;
/**
* The generic class autoloader is a slightly enhanced version of the
@@ -28,25 +28,25 @@ class GenericLoader
* @static
* @var string
*/
- private $_defaultPath = '';
+ private $defaultPath = '';
/**
* The list of available top-level namespaces.
* @var array
*/
- private $_namespaces = array();
+ private $namespaces = array();
/**
* The file extensions in the namespaces.
* @var array
*/
- private $_extensions = array();
+ private $extensions = array();
/**
* The namespace separator
* @var string
*/
- private $_namespaceSeparator = '\\';
+ private $namespaceSeparator = '\\';
/**
* Constructs the autoloader.
@@ -56,14 +56,14 @@ class GenericLoader
*/
public function __construct($defaultPath = './', $namespaceSeparator = '\\')
{
- $this->_namespaceSeparator = $namespaceSeparator;
+ $this->namespaceSeparator = $namespaceSeparator;
$length = strlen($defaultPath);
if($length == 0 || $defaultPath[$length - 1] != '/')
{
$defaultPath .= '/';
}
- $this->_defaultPath = $defaultPath;
+ $this->defaultPath = $defaultPath;
} // end __construct();
/**
@@ -75,9 +75,9 @@ public function __construct($defaultPath = './', $namespaceSeparator = '\\')
*/
public function addNamespace($namespace, $path = null, $extension = '.php')
{
- if(isset($this->_namespaces[(string)$namespace]))
+ if(isset($this->namespaces[(string)$namespace]))
{
- throw new RuntimeException('The namespace '.$namespace.' is already added.');
+ throw new DomainException('The namespace '.$namespace.' is already added.');
}
if($path !== null)
{
@@ -86,13 +86,13 @@ public function addNamespace($namespace, $path = null, $extension = '.php')
{
$path .= '/';
}
- $this->_namespaces[(string)$namespace] = $path;
+ $this->namespaces[(string)$namespace] = $path;
}
else
{
- $this->_namespaces[(string)$namespace] = $this->_defaultPath;
+ $this->namespaces[(string)$namespace] = $this->defaultPath;
}
- $this->_extensions[(string)$namespace] = $extension;
+ $this->extensions[(string)$namespace] = $extension;
} // end addNamespace();
/**
@@ -102,7 +102,7 @@ public function addNamespace($namespace, $path = null, $extension = '.php')
*/
public function hasNamespace($namespace)
{
- return isset($this->_namespaces[(string)$namespace]);
+ return isset($this->namespaces[(string)$namespace]);
} // end hasNamespace();
/**
@@ -112,12 +112,12 @@ public function hasNamespace($namespace)
*/
public function removeNamespace($namespace)
{
- if(!isset($this->_namespaces[(string)$namespace]))
+ if(!isset($this->namespaces[(string)$namespace]))
{
- throw new RuntimeException('The namespace '.$namespace.' is not available.');
+ throw new DomainException('The namespace '.$namespace.' is not available.');
}
- unset($this->_namespaces[(string)$namespace]);
- unset($this->_extensions[(string)$namespace]);
+ unset($this->namespaces[(string)$namespace]);
+ unset($this->extensions[(string)$namespace]);
} // end removeNamespace();
/**
@@ -127,7 +127,7 @@ public function removeNamespace($namespace)
*/
public function setNamespaceSeparator($sep)
{
- $this->_namespaceSeparator = $sep;
+ $this->namespaceSeparator = $sep;
} // end setNamespaceSeparator();
/**
@@ -137,7 +137,7 @@ public function setNamespaceSeparator($sep)
*/
public function getNamespaceSeparator()
{
- return $this->_namespaceSeparator;
+ return $this->namespaceSeparator;
} // end getNamespaceSeparator();
/**
@@ -152,7 +152,7 @@ public function setDefaultPath($defaultPath)
{
$defaultPath .= '/';
}
- $this->_defaultPath = $defaultPath;
+ $this->defaultPath = $defaultPath;
} // end setDefaultPath();
/**
@@ -162,7 +162,7 @@ public function setDefaultPath($defaultPath)
*/
public function getDefaultPath()
{
- return $this->_defaultPath;
+ return $this->defaultPath;
} // end getDefaultPath();
/**
@@ -189,19 +189,19 @@ public function unregister()
*/
public function loadClass($className)
{
- $className = ltrim($className, $this->_namespaceSeparator);
- $match = strstr($className, $this->_namespaceSeparator, true);
+ $className = ltrim($className, $this->namespaceSeparator);
+ $match = strstr($className, $this->namespaceSeparator, true);
- if(false === $match || !isset($this->_namespaces[$match]))
+ if(false === $match || !isset($this->namespaces[$match]))
{
return false;
}
- $rest = strrchr($className, $this->_namespaceSeparator);
+ $rest = strrchr($className, $this->namespaceSeparator);
$replacement =
- str_replace($this->_namespaceSeparator, '/', substr($className, 0, strlen($className) - strlen($rest))).
- str_replace(array('_', $this->_namespaceSeparator), '/', $rest);
+ str_replace($this->namespaceSeparator, '/', substr($className, 0, strlen($className) - strlen($rest))).
+ str_replace(array('_', $this->namespaceSeparator), '/', $rest);
- require($this->_namespaces[$match].$replacement.$this->_extensions[$match]);
+ require($this->namespaces[$match].$replacement.$this->extensions[$match]);
return true;
} // end loadClass();
} // end GenericLoader;
View
13 src/Opl/Autoloader/PHARLoader.php
@@ -26,7 +26,12 @@ class PHARLoader
* @var array
* @internal
*/
- protected $_classMap;
+ protected $classMap;
+ /**
+ * The path to the PHAR file (for testing purposes only.
+ * @var string
+ */
+ protected $path = __FILE__;
/**
* Creates the class map loader and loads the map into the memory.
@@ -37,7 +42,7 @@ class PHARLoader
*/
public function __construct(array $classMap)
{
- $this->_classMap = $classMap;
+ $this->classMap = $classMap;
} // end __construct();
/**
@@ -64,11 +69,11 @@ public function unregister()
*/
public function loadClass($className)
{
- if(!isset($this->_classMap[$className]))
+ if(!isset($this->classMap[$className]))
{
return false;
}
- require('phar://'.__FILE__.'/'.$this->_classMap[$className][1]);
+ require('phar://'.$this->path.'/'.$this->classMap[$className][1]);
return true;
} // end loadClass();
} // end PHARLoader;
View
151 src/Opl/Autoloader/Toolset/AbstractTool.php
@@ -0,0 +1,151 @@
+<?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\Toolset;
+use Opl\Autoloader\Exception\TranslationException;
+use DomainException;
+
+/**
+ * The class provides a common base implementation for all the autoloader-related
+ * tools. IT allows to define namespaces, and translate the class names into files.
+ *
+ * @author Tomasz Jędrzejewski
+ * @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
+ * @license http://www.invenzzia.org/license/new-bsd New BSD License
+ */
+abstract class AbstractTool
+{
+ /**
+ * The list of available top-level namespaces.
+ * @var array
+ */
+ protected $namespaces = array();
+
+ /**
+ * The file extensions in the namespaces.
+ * @var array
+ */
+ protected $extensions = array();
+ /**
+ * The namespace separator
+ * @var string
+ */
+ private $namespaceSeparator = '\\';
+
+ /**
+ * Registers a new top-level namespace to match.
+ *
+ * @param string $namespace The namespace name to add.
+ * @param string $path The path to the namespace (without the namespace name itself).
+ * @param string $extension The namespace file extension.
+ */
+ public function addNamespace($namespace, $path, $extension = '.php')
+ {
+ if(isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is already added.');
+ }
+ $length = strlen($path);
+ if($length == 0 || $path[$length - 1] != '/')
+ {
+ $path .= '/';
+ }
+ $this->namespaces[(string)$namespace] = $path;
+ $this->extensions[(string)$namespace] = $extension;
+ } // end addNamespace();
+
+ /**
+ * Checks if the specified top-level namespace is available.
+ *
+ * @param string $namespace The namespace name to check.
+ */
+ public function hasNamespace($namespace)
+ {
+ return isset($this->namespaces[(string)$namespace]);
+ } // end hasNamespace();
+
+ /**
+ * Removes a registered top-level namespace.
+ *
+ * @param string $namespace The namespace name to remove.
+ */
+ public function removeNamespace($namespace)
+ {
+ if(!isset($this->namespaces[(string)$namespace]))
+ {
+ throw new DomainException('The namespace '.$namespace.' is not available.');
+ }
+ unset($this->namespaces[(string)$namespace]);
+ unset($this->extensions[(string)$namespace]);
+ } // end removeNamespace();
+
+ /**
+ * Changes the namespace separator.
+ *
+ * @param string $separator The new separator
+ * @return AbstractTool Fluent interface.
+ */
+ public function setNamespaceSeparator($separator)
+ {
+ $this->namespaceSeparator = (string)$separator;
+ return $this;
+ } // end setNamespaceSeparator();
+
+ /**
+ * Returns the current namespace separator.
+ *
+ * @return string
+ */
+ public function getNamespaceSeparator()
+ {
+ return $this->namespaceSeparator;
+ } // end getNamespaceSeparator();
+
+ /**
+ * Translates the class name to the file name, using the algorithm from
+ * the Universal Loader to allow the best precision. If the class could
+ * not be translated, an exception is thrown.
+ *
+ * @throws TranslationException
+ * @param string $className The class name.
+ * @param boolean $withNamespacePath Whether to include the namespace path into the result.
+ * @param string The file name.
+ */
+ public function toFilename($className, $withNamespacePath = true)
+ {
+ $className = ltrim($className, $this->namespaceSeparator);
+
+ // PSR-0 conventions
+ foreach($this->namespaces as $namespace => $path)
+ {
+ if(0 === strpos($className, $namespace))
+ {
+ if(strpos($className, $this->namespaceSeparator) !== false)
+ {
+ $rest = strrchr($className, $this->namespaceSeparator);
+ $replacement =
+ str_replace($this->namespaceSeparator, '/', substr($className, 0, strlen($className) - strlen($rest))).
+ str_replace(array('_', $this->namespaceSeparator), '/', $rest);
+ }
+ else
+ {
+ $replacement = str_replace('_', '/', $className);
+ }
+ if(!$withNamespacePath)
+ {
+ return $replacement.$this->extensions[$namespace];
+ }
+ return $path.$replacement.$this->extensions[$namespace];
+ }
+ }
+ throw new TranslationException('Namespace not found for the class: \''.$className.'\'.');
+ } // end toFilename();
+} // end AbstractTool;
View
37 src/Opl/Autoloader/ClassMapBuilder.php → ...pl/Autoloader/Toolset/ClassMapBuilder.php
@@ -9,7 +9,7 @@
* Copyright (c) Invenzzia Group <http://www.invenzzia.org>
* and other contributors. See website for details.
*/
-namespace Opl\Autoloader;
+namespace Opl\Autoloader\Toolset;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
@@ -20,7 +20,7 @@
* @copyright Invenzzia Group <http://www.invenzzia.org/> and contributors.
* @license http://www.invenzzia.org/license/new-bsd New BSD License
*/
-class ClassMapBuilder
+class ClassMapBuilder extends AbstractTool
{
/**
* The generated map.
@@ -48,22 +48,37 @@ public function clearMap()
{
$this->map = array();
} // end clearMap();
+
+ /**
+ * Constructs the map from the registered namespaces.
+ *
+ * @return array The list of errors.
+ */
+ public function buildMap()
+ {
+ $errors = array();
+ foreach($this->namespaces as $namespace => $void)
+ {
+ $nsErrors = $this->processNamespace($namespace);
+ foreach($nsErrors as $error)
+ {
+ $errors[] = $error;
+ }
+ }
+ return $errors;
+ } // end buildMap();
/**
- * Adds the specified top-level namespace to the map. Returns the list of encountered
+ * Processes the specified top-level namespace to the map. Returns the list of encountered
* errors. If the class is already defined in the map, it is overwritten.
*
* @param string $namespaceName The namespace name and the name of the top-level directory.
- * @param string $path The path to the namespace directory.
- * @param string $extension PHP file extension.
* @return array
*/
- public function addNamespace($namespaceName, $path, $extension = '.php')
+ protected function processNamespace($namespaceName)
{
- if($path[strlen($path) - 1] != '/')
- {
- $path .= '/';
- }
+ $path = $this->namespaces[$namespaceName];
+ $extension = $this->extensions[$namespaceName];
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path.$namespaceName)
@@ -97,6 +112,8 @@ public function addNamespace($namespaceName, $path, $extension = '.php')
return $errors;
} // end addNamespace();
+
+
/**
* Processes a single PHP file, attempting to load the class name
View
282 src/Opl/Autoloader/Toolset/Configuration.php
@@ -0,0 +1,282 @@
+<?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\Toolset;
+use Opl\Autoloader\Exception\FileFormatException;
+use Opl\Autoloader\Exception\FileNotFoundException;
+use OutOfBoundsException;
+
+/**
+ * This class allows to parse the official Open Power Autoloader configuration
+ * files that are used by the CLI 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 Configuration
+{
+ /**
+ * The exported PHP file header.
+ * @var string
+ */
+ protected $fileHeader;
+ /**
+ * The exported PHP file footer.
+ * @var string
+ */
+ protected $fileFooter;
+ /**
+ * The separators and their namespaces
+ * @var array[string][string]
+ */
+ protected $separators;
+ /**
+ * The list of defined export files.
+ * @var string[string]
+ */
+ protected $files;
+ /**
+ * Do we have simple namespaces only in the configuration?
+ * @var boolean
+ */
+ protected $simpleNamespacesOnly = true;
+
+ /**
+ * Imports the configuration file content into the memory.
+ *
+ * @throws FileNotFoundException
+ * @throws FileFormatException
+ * @param type $configFile
+ */
+ public function __construct($configFile)
+ {
+ libxml_use_internal_errors(true);
+ $document = \simplexml_load_file($configFile);
+ foreach (libxml_get_errors() as $error)
+ {
+ if($error->level != LIBXML_ERR_WARNING)
+ {
+ libxml_clear_errors();
+ throw new FileFormatException('An error occured while parsing \''.$configFile.'\': '.$error->message.' on line '.($error->line - 1));
+ }
+ }
+ if(!is_object($document))
+ {
+ throw new FileNotFoundException('Cannot open the file: '.$configFile);
+ }
+
+ if(isset($document->{'file-header'}))
+ {
+ $this->fileHeader = trim((string)$document->{'file-header'}).PHP_EOL;
+ }
+ else
+ {
+ $this->fileHeader = '<?php'.PHP_EOL;
+ }
+ if(isset($document->{'file-footer'}))
+ {
+ $this->fileFooter = PHP_EOL.trim((string)$document->{'file-footer'});
+ }
+
+ if(isset($document->{'export-files'}))
+ {
+ foreach($document->{'export-files'}->{'file'} as $file)
+ {
+ $this->processFileTag($file);
+ }
+ }
+ if(isset($document->separator))
+ {
+ foreach($document->separator as $separatorTag)
+ {
+ $this->processSeparatorTag($separatorTag);
+ }
+ }
+ } // end __construct();
+
+ /**
+ * Processes the <file> tag.
+ *
+ * @internal
+ * @throws FileFormatException
+ * @param SimpleXMLElement $fileTag
+ */
+ protected function processFileTag($fileTag)
+ {
+ if(!isset($fileTag['type']))
+ {
+ throw new FileFormatException('The <file> tag must have the \'type\' attribute.');
+ }
+ $this->files[(string)$fileTag['type']] = (string)$fileTag;
+ } // end processFileTag();
+
+ /**
+ * Processes the <separator> tag and its contents.
+ *
+ * @internal
+ * @throws FileFormatException
+ * @param SimpleXMLElement $separatorTag
+ */
+ protected function processSeparatorTag($separatorTag)
+ {
+ if(!isset($separatorTag['value']))
+ {
+ throw new FileFormatException('The <separator> tag must have the \'value\' attribute.');
+ }
+
+ $separatorValue = (string)$separatorTag['value'];
+ $namespaces = array();
+
+ foreach($separatorTag->{'namespace'} as $namespaceTag)
+ {
+ if(!isset($namespaceTag['name']))
+ {
+ throw new FileFormatException('The <namespace> tag must have the \'name\' attribute.');
+ }
+ $name = (string)$namespaceTag['name'];
+
+ // If the name contains the namespace separator, we cannot use GenericLoader any longer.
+ if(strpos($name, $separatorValue) !== false)
+ {
+ $this->simpleNamespacesOnly = false;
+ }
+
+ $extension = '.php';
+ if(isset($namespaceTag['extension']))
+ {
+ $extension = (string) $namespaceTag['extension'];
+ }
+
+ $path = (string)$namespaceTag;
+
+ $namespaces[$name] = array(
+ 'path' => $path,
+ 'extension' => $extension
+ );
+ }
+
+ $this->separators[$separatorValue] = $namespaces;
+ } // end processSeparatorTag();
+
+ /**
+ * Returns the list of available namespace separators.
+ *
+ * @return string[]
+ */
+ public function getSeparators()
+ {
+ return array_keys($this->separators);
+ } // end getSeparators();
+
+ /**
+ * Returns the namespaces defined for the given namespace separator. Each namespace
+ * is an array consisting of two keys: 'path' and 'extension'.
+ *
+ * @throws OutOfBoundsException
+ * @param string $separator The namespace separator
+ * @return array
+ */
+ public function getSeparatorNamespaces($separator)
+ {
+ if(!isset($this->separators[$separator]))
+ {
+ throw new OutOfBoundsException('The separator \''.$separator.' is not defined.');
+ }
+ return $this->separators[$separator];
+ } // end getSeparatorNamespaces();
+
+ /**
+ * Returns all the files defined by the configuration file. If the optional
+ * argument is set to true, the list does not contain the reserved special file
+ * types.
+ *
+ * @param boolean $filterSpecial Do we skip special file types?
+ * @return string[string]
+ */
+ public function getFiles($filterSpecial = false)
+ {
+ if(!$filterSpecial)
+ {
+ return $this->files;
+ }
+ $result = array();
+ $ignore = array('serialized-class-map', 'chdb-class-map', 'core-dump', 'core-export');
+ foreach($this->files as $name => $file)
+ {
+ if(!in_array($name, $ignore))
+ {
+ $result[$name] = $file;
+ }
+ }
+ return $result;
+ } // end getFiles();
+
+ /**
+ * Returns the file path defined for the given file type.
+ *
+ * @throws OutOfBoundsException If the type is not defined.
+ * @param string $type The type identifier.
+ * @return string
+ */
+ public function getFile($type)
+ {
+ if(!isset($this->files[$type]))
+ {
+ throw new OutOfBoundsException('The file type \''.$type.'\' is not defined.');
+ }
+ return $this->files[$type];
+ } // end getFile();
+
+ /**
+ * Checks if the given file type is defined.
+ *
+ * @param string $type The type identifier.
+ * @return boolean
+ */
+ public function hasFile($type)
+ {
+ return isset($this->files[$type]);
+ } // end hasFile();
+
+ /**
+ * Returns the stub file header with the autoloading code.
+ *
+ * @return string
+ */
+ public function getFileHeader()
+ {
+ return $this->fileHeader;
+ } // end getFileHeader();
+
+ /**
+ * Returns the stub file footer with the autoloading code.
+ *
+ * @return string
+ */
+ public function getFileFooter()
+ {
+ return $this->fileFooter;
+ } // end getFileFooter();
+
+ /**
+ * Returns true, if the configuration file defines simple namespaces only.
+ * A simple namespace does not contain the namespace separator in its name,
+ * so it can be only a top-level namespace. <tt>GenericLoader</tt> does not
+ * support complex namespaces and this is why we need this information.
+ *
+ * @return boolean
+ */
+ public function hasSimpleNamespacesOnly()
+ {
+ return $this->simpleNamespacesOnly;
+ } // end hasSimpleNamespacesOnly();
+} // end Configuration;
View
131 src/Opl/Autoloader/Toolset/CoreDump.php
@@ -0,0 +1,131 @@
+<?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.