Skip to content

Commit

Permalink
API Implement kernel nesting
Browse files Browse the repository at this point in the history
  • Loading branch information
Damian Mooyman committed Jun 20, 2017
1 parent fc7188d commit 2f6336a
Show file tree
Hide file tree
Showing 13 changed files with 264 additions and 75 deletions.
1 change: 0 additions & 1 deletion src/Control/Director.php
Expand Up @@ -188,7 +188,6 @@ public static function test(
$cookies = array(),
&$request = null
) {

Config::nest();
Injector::nest();

Expand Down
6 changes: 4 additions & 2 deletions src/Core/AppKernel.php
Expand Up @@ -13,6 +13,7 @@
use SilverStripe\Core\Config\ConfigLoader;
use SilverStripe\Core\Config\CoreConfigFactory;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Injector\InjectorLoader;
use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
use SilverStripe\Core\Manifest\ClassLoader;
use SilverStripe\Core\Manifest\ClassManifest;
Expand All @@ -38,9 +39,10 @@ public function __construct($flush = false)

// Initialise the dependency injector as soon as possible, as it is
// subsequently used by some of the following code
$injectorLoader = InjectorLoader::inst();
$injector = new Injector(array('locator' => SilverStripeServiceConfigurationLocator::class));
$this->setContainer($injector);
Injector::set_inst($injector);
$injectorLoader->pushManifest($injector);
$this->setInjectorLoader($injectorLoader);

// Manifest cache factory
$manifestCacheFactory = $this->buildManifestCacheFactory();
Expand Down
2 changes: 1 addition & 1 deletion src/Core/Config/Config.php
Expand Up @@ -87,7 +87,7 @@ public static function unnest()
{
// Unnest unless we would be left at 0 manifests
$loader = ConfigLoader::inst();
if ($loader->countManifests() < 2) {
if ($loader->countManifests() <= 1) {
user_error(
"Unable to unnest root Config, please make sure you don't have mis-matched nest/unnest",
E_USER_WARNING
Expand Down
27 changes: 22 additions & 5 deletions src/Core/Config/ConfigLoader.php
Expand Up @@ -82,14 +82,31 @@ public function countManifests()
}

/**
* Nest the current manifest
* Nest the config loader and activates it
*
* @return ConfigCollectionInterface
* @return static
*/
public function nest()
{
$manifest = $this->getManifest()->nest();
$this->pushManifest($manifest);
return $manifest;
// Nest config
$manifest = clone $this->getManifest();

// Create new blank loader with new stack (top level nesting)
$newLoader = new self;
$newLoader->pushManifest($manifest);

// Activate new loader
return $newLoader->activate();
}

/**
* Mark this instance as the current instance
*
* @return $this
*/
public function activate()
{
static::$instance = $this;
return $this;
}
}
44 changes: 39 additions & 5 deletions src/Core/CoreKernel.php
Expand Up @@ -5,6 +5,7 @@
use InvalidArgumentException;
use SilverStripe\Core\Config\ConfigLoader;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Injector\InjectorLoader;
use SilverStripe\Core\Manifest\ClassLoader;
use SilverStripe\Core\Manifest\ModuleLoader;
use SilverStripe\View\ThemeResourceLoader;
Expand All @@ -14,6 +15,11 @@
*/
class CoreKernel implements Kernel
{
/**
* @var Kernel
*/
protected $nestedFrom = null;

/**
* @var Injector
*/
Expand All @@ -39,6 +45,11 @@ class CoreKernel implements Kernel
*/
protected $configLoader = null;

/**
* @var InjectorLoader
*/
protected $injectorLoader = null;

/**
* @var ThemeResourceLoader
*/
Expand All @@ -54,21 +65,44 @@ public function shutdown()

public function nest()
{
// TODO: Implement nest() method.
// Clone this kernel, nesting config / injector manifest containers
$kernel = clone $this;
$kernel->setConfigLoader($this->configLoader->nest());
$kernel->setInjectorLoader($this->injectorLoader->nest());
return $kernel;
}

public function activate()
{
$this->configLoader->activate();
$this->injectorLoader->activate();
return $this;
}

public function getNestedFrom()
{
return $this->nestedFrom;
}

public function getContainer()
{
return $this->container;
return $this->getInjectorLoader()->getManifest();
}

public function setContainer(Injector $container)
public function setInjectorLoader(InjectorLoader $injectorLoader)
{
$this->container = $container;
$container->registerService($this, Kernel::class);
$this->injectorLoader = $injectorLoader;
$injectorLoader
->getManifest()
->registerService($this, Kernel::class);
return $this;
}

public function getInjectorLoader()
{
return $this->injectorLoader;
}

public function getClassLoader()
{
return $this->classLoader;
Expand Down
14 changes: 9 additions & 5 deletions src/Core/HTTPApplication.php
Expand Up @@ -106,10 +106,14 @@ public function handle(HTTPRequest $request)
*/
public function execute(callable $callback)
{
return $this->callMiddleware(function () use ($callback) {
// Pre-request boot
$this->getKernel()->boot();
return call_user_func($callback);
});
try {
return $this->callMiddleware(function () use ($callback) {
// Pre-request boot
$this->getKernel()->boot();
return call_user_func($callback);
});
} finally {
$this->getKernel()->shutdown();
}
}
}
32 changes: 11 additions & 21 deletions src/Core/Injector/Injector.php
Expand Up @@ -236,18 +236,7 @@ public function __construct($config = null)
*/
public static function inst()
{
return self::$instance;
}

/**
* Sets the default global injector instance.
*
* @param Injector $instance
* @return Injector Reference to new active Injector instance
*/
public static function set_inst(Injector $instance)
{
return self::$instance = $instance;
return InjectorLoader::inst()->getManifest();
}

/**
Expand All @@ -262,11 +251,10 @@ public static function set_inst(Injector $instance)
*/
public static function nest()
{
$current = self::$instance;

$new = clone $current;
$new->nestedFrom = $current;
return self::set_inst($new);
// Clone current injector and nest
$new = clone self::inst();
InjectorLoader::inst()->pushManifest($new);
return $new;
}

/**
Expand All @@ -277,15 +265,17 @@ public static function nest()
*/
public static function unnest()
{
if (self::inst()->nestedFrom) {
self::set_inst(self::inst()->nestedFrom);
} else {
// Unnest unless we would be left at 0 manifests
$loader = InjectorLoader::inst();
if ($loader->countManifests() <= 1) {
user_error(
"Unable to unnest root Injector, please make sure you don't have mis-matched nest/unnest",
E_USER_WARNING
);
} else {
$loader->popManifest();
}
return self::inst();
return static::inst();
}

/**
Expand Down
109 changes: 109 additions & 0 deletions src/Core/Injector/InjectorLoader.php
@@ -0,0 +1,109 @@
<?php

namespace SilverStripe\Core\Injector;

use BadMethodCallException;

/**
* Registers chained injectors
*/
class InjectorLoader
{
/**
* @internal
* @var self
*/
private static $instance;

/**
* @var Injector[] map of injector instances
*/
protected $manifests = array();

/**
* @return self
*/
public static function inst()
{
return self::$instance ? self::$instance : self::$instance = new self();
}

/**
* Returns the currently active class manifest instance that is used for
* loading classes.
*
* @return Injector
*/
public function getManifest()
{
if (empty($this->manifests)) {
throw new BadMethodCallException("No injector manifests available");
}
return $this->manifests[count($this->manifests) - 1];
}

/**
* Returns true if this class loader has a manifest.
*
* @return bool
*/
public function hasManifest()
{
return (bool)$this->manifests;
}

/**
* Pushes a class manifest instance onto the top of the stack.
*
* @param Injector $manifest
*/
public function pushManifest(Injector $manifest)
{
$this->manifests[] = $manifest;
}

/**
* @return Injector
*/
public function popManifest()
{
return array_pop($this->manifests);
}

/**
* Check number of manifests
*
* @return int
*/
public function countManifests()
{
return count($this->manifests);
}

/**
* Nest the config loader
*
* @return static
*/
public function nest()
{
// Nest config
$manifest = $this->getManifest()->nest();

// Create new blank loader with new stack (top level nesting)
$newLoader = new self;
$newLoader->pushManifest($manifest);

// Activate new loader
$newLoader->activate();
return $newLoader;
}

/**
* Mark this instance as the current instance
*/
public function activate()
{
static::$instance = $this;
}
}

0 comments on commit 2f6336a

Please sign in to comment.