Created
February 24, 2014 10:05
-
-
Save kapv89/9184949 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php namespace div\Core; | |
use Illuminate\Container\Container; | |
use ReflectionFunction; | |
use Closure; | |
use div; | |
class Module extends Container { | |
protected static $scriptClosureMap = []; | |
protected $name; | |
protected $root; | |
protected $config; | |
protected $vent; | |
protected $modules = []; | |
protected $starter = null; | |
protected $initialized = false; | |
protected $started = false; | |
const initializing = 'initializing'; | |
const initialized = 'initialized'; | |
const starting = 'starting'; | |
const started = 'started'; | |
const stopping = 'stopping'; | |
const stopped = 'stopped'; | |
public function __construct($name, $root, $config = null, Closure $starter = null, Vent $vent = null) | |
{ | |
$this->name = $name; | |
$this->root = realpath($root); | |
$this->config = $config instanceof Config ? $config : new Config((array) $config); | |
$this->starter = $starter; | |
$this->vent = $vent ? : new Vent; | |
} | |
public function getName() | |
{ | |
return $this->name; | |
} | |
public function path($path = '') | |
{ | |
return realpath(strpos($path, '/') === 0 ? $path : $this['root'] . '/' . $path); | |
} | |
public function config($key = null, $default = null) | |
{ | |
return $this->config->get($key, $default); | |
} | |
/** event methods **/ | |
public function on($event, Closure $callback) | |
{ | |
$this->vent->on($event, $callback); | |
return $this; | |
} | |
public function off($event) | |
{ | |
$this->vent->off($event); | |
} | |
public function fire($event, $args = array()) | |
{ | |
$args = array_merge([$this], $args); | |
$this->vent->fire($event, $args); | |
return $this; | |
} | |
/** module nesting methods **/ | |
public function loadModules(array $modules) | |
{ | |
foreach ($modules as $key => $module) { | |
if(is_string($key)) { | |
$module = (array) $module; | |
$module['name'] = $key; | |
} | |
$this->loadModule($module); | |
} | |
return $this; | |
} | |
public function loadModule($module) | |
{ | |
if (! $module instanceof Module) { | |
if (is_string($module)) { | |
$module = ['name' => $module]; | |
} | |
$module = $this->createModule((array) $module); | |
} | |
if (in_array($module->getName(), $this->modules)) { | |
// stop existing module | |
$this[$module->getName()]->stop(); | |
} else { | |
// append the module to the list of modules | |
$this->modules[] = $module->getName(); | |
} | |
$this[$module->getName()] = $module; | |
return $this; | |
} | |
protected function createModule(array $conf) | |
{ | |
if (! isset($conf['name'])) { | |
throw new \InvalidArgumentException('A Module needs a name ' : json_encode($conf)); | |
} | |
$name = $conf['name']; | |
$baseDir = $this->config('path.modules', 'modules'); | |
$root = isset($conf['root']) ? $conf['root'] : $this->path($baseDir.'/'.$name); | |
$configFile = isset($conf['config']) ? $root.'/'.$conf['config'] : $root.'/'.'config.php'; | |
if (file_exists($configFile)) { | |
$config = include $configFile; | |
} else { | |
$config = []; | |
} | |
$type = isset($conf['type']) ? $conf['type'] : __CLASS__; | |
$class = $this->getAlias($type); | |
if (trim('\\', $class) !== __CLASS__ and ! is_subclass_of($class, __CLASS__)) { | |
throw new \InvalidArgumentException('Module Class should be a subtype of div\Core\Module : ' . $class); | |
} | |
$starter = isset($conf['starter']) ? $conf['starter'] : null; | |
$vent = isset($conf['vent']) ? $conf['vent'] : null | |
return $this->make($type, [$name, $root, $config, $starter, $vent]); | |
} | |
/** lifecycle methods **/ | |
protected function setStarter(Closure $starter = null) | |
{ | |
if ($starter instanceof Closure) { | |
$this->starter = $starter; | |
} elseif (file_exists($startFile = $this->path($this->config('path.start', 'start.php')))) { | |
$this->starter = include $startFile; | |
} elseif(! $this->starter instanceof Closure) { | |
$this->starter = function () { }; | |
} | |
// bind the module as $this to starter | |
$this->starter = $this->starter->bindTo($this, null); | |
} | |
protected function initModules() | |
{ | |
// initialize all the submodules too | |
foreach($this->modules as $name) { | |
$this[$name]->init(); | |
} | |
} | |
public function init(Closure $starter = null) | |
{ | |
if ($this->initialized) { | |
return $this; | |
} | |
$this->fire(static::initializing); | |
$this->setStarter($starter); | |
$this->initModules(); | |
$this->initialized = true; | |
$this->fire(static::initialized); | |
return $this | |
} | |
///// | |
public function getStarter() | |
{ | |
return $this->starter; | |
} | |
///// | |
protected function runStarter($arg) | |
{ | |
if(is_array($arg)) { | |
$deps = $arg; | |
$parent = null; | |
} elseif($arg instanceof Module) { | |
$deps = []; | |
$parent = $arg; | |
} else { | |
throw new \InvalidArgumentException( | |
'Module::start() only takes dependencies or a parent module for supplying dependencies as argument' | |
); | |
} | |
// start the module itself | |
if($parent) { | |
$deps = array_map( | |
function ($p) use ($parent) { return $parent[$p->getName()]; }, | |
((new ReflectionFunction($this->starter))->getParameters() | |
); | |
} | |
div\call($this->starter, $deps); | |
} | |
protected function startModules() | |
{ | |
// start all the submodules | |
foreach ($this->modules as $name) { | |
$this[$name]->start($this); | |
} | |
} | |
public function start($arg) | |
{ | |
// don't start the module if it is already started | |
if ($this->started) { | |
return $this; | |
} | |
$this->init(); | |
$this->fire(static::starting); | |
$this->startModules(); | |
$this->runStarter($arg); | |
$this->started = true; | |
$this->fire(static::started); | |
return $this; | |
} | |
///// | |
protected function stopModules() | |
{ | |
foreach ($this->modules as $name) { | |
$this[$name]->stop(); | |
} | |
} | |
public function stop() | |
{ | |
$this->fire(static::stopping); | |
$this->stopModules(); | |
$this->initialized = false; | |
$this->started = false; | |
$this->fire(static::stopped); | |
return $this; | |
} | |
///// | |
public function execScript($script, array $args = array()) { | |
$script = realpath($script); | |
if (! isset(static::$scriptClosureMap[$script])) { | |
static::$scriptClosureMap[$script] = include $script; | |
} | |
return $this->exec(static::$scriptClosureMap[$script], $args); | |
} | |
public function exec(Closure $closure, array $args = array()) { | |
div\call($closure->bindTo($this), $args); | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment