diff --git a/CHANGELOG.md b/CHANGELOG.md
index 314529cc..ddc22f92 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,7 @@ dev-master
### Features
+- [general] The shell supports being embedded as a dependency
- [node:edit] New command `node:edit` enables editing of entire node
alpha-4
diff --git a/features/bootstrap/FeatureContext.php b/features/bootstrap/FeatureContext.php
index 175947ad..7ff2c64e 100644
--- a/features/bootstrap/FeatureContext.php
+++ b/features/bootstrap/FeatureContext.php
@@ -50,7 +50,7 @@ public function beforeScenario()
$session = $this->getSession(null, true);
- $this->applicationTester = new ApplicationTester($this->application);
+ $this->applicationTester = new ApplicationTester();
$this->applicationTester->run(array(
'--transport' => 'jackrabbit',
'--no-interaction' => true,
diff --git a/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php b/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php
new file mode 100644
index 00000000..0fe61b98
--- /dev/null
+++ b/spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php
@@ -0,0 +1,20 @@
+beConstructedWith(EmbeddedApplication::MODE_COMMAND);
+ }
+
+ function it_is_initializable()
+ {
+ $this->shouldHaveType('PHPCR\Shell\Console\Application\EmbeddedApplication');
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php b/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php
new file mode 100644
index 00000000..9b20e06a
--- /dev/null
+++ b/src/PHPCR/Shell/Console/Application/EmbeddedApplication.php
@@ -0,0 +1,71 @@
+
+ */
+class EmbeddedApplication extends ShellApplication
+{
+ const MODE_SHELL = 'shell';
+ const MODE_COMMAND = 'command';
+
+ protected $mode = self::MODE_SHELL;
+
+ /**
+ * The $mode can be one of EmbeddedApplication::MODE_SHELL or EmbeddedApplication::MODE_COMMAND.
+ *
+ * - Shell mode initializes the whole environement
+ * - Command mode initailizes only enough to run commands
+ *
+ * @param string $mode
+ */
+ public function __construct($mode)
+ {
+ parent::__construct(SessionApplication::APP_NAME, SessionApplication::APP_VERSION);
+ $this->mode = $mode;
+ $this->setAutoExit(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public function init()
+ {
+ if (true === $this->initialized) {
+ return;
+ }
+
+ $this->registerPhpcrCommands();
+
+ if ($this->mode === self::MODE_SHELL) {
+ $this->registerShellCommands();
+ }
+
+ $this->initialized = true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function getDefaultCommand()
+ {
+ return 'shell:path:show';
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected function registerEventListeners()
+ {
+ $this->dispatcher->addSubscriber(new Subscriber\ProfileFromSessionInputSubscriber());
+ $this->dispatcher->addSubscriber(new Subscriber\ExceptionSubscriber());
+ $this->dispatcher->addSubscriber(new Subscriber\AliasSubscriber($this->getHelperSet()));
+ $this->dispatcher->addSubscriber(new Subscriber\AutoSaveSubscriber());
+ }
+}
diff --git a/src/PHPCR/Shell/Console/Application/SessionApplication.php b/src/PHPCR/Shell/Console/Application/SessionApplication.php
index 0018736c..d43d6098 100644
--- a/src/PHPCR/Shell/Console/Application/SessionApplication.php
+++ b/src/PHPCR/Shell/Console/Application/SessionApplication.php
@@ -28,10 +28,7 @@ public function __construct()
{
parent::__construct(self::APP_NAME, self::APP_VERSION);
- $this->shellApplication = new ShellApplication(
- self::APP_NAME,
- self::APP_VERSION
- );
+ $this->shellApplication = new ShellApplication();
$command = new ShellCommand($this->shellApplication);
$command->setApplication($this);
diff --git a/src/PHPCR/Shell/Console/Application/ShellApplication.php b/src/PHPCR/Shell/Console/Application/ShellApplication.php
index 835063db..9fe76ec0 100644
--- a/src/PHPCR/Shell/Console/Application/ShellApplication.php
+++ b/src/PHPCR/Shell/Console/Application/ShellApplication.php
@@ -56,11 +56,11 @@ class ShellApplication extends Application
*
* {@inheritDoc}
*/
- public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
+ public function __construct()
{
- parent::__construct($name, $version);
+ parent::__construct(SessionApplication::APP_NAME, SessionApplication::APP_VERSION);
$this->profile = new Profile();
- $this->dispatcher = new EventDispatcher();
+ $this->setDispatcher($this->dispatcher = new EventDispatcher());
$this->transportRegistry = new TransportRegistry();
$this->registerTransports();
$this->registerHelpers();
@@ -101,6 +101,9 @@ public function setShowUnsupported($boolean)
* Note that we do this "lazily" because we instantiate the ShellApplication early,
* before the SessionInput has been set. The SessionInput must be set before we
* can initialize the application.
+ *
+ * @todo: The above scenario is no longer true, we use a Profile. So maybe it can
+ * be refactored.
*/
public function init()
{
@@ -108,7 +111,8 @@ public function init()
return;
}
- $this->registerCommands();
+ $this->registerPhpcrCommands();
+ $this->registerShellCommands();
$event = new ApplicationInitEvent($this);
$this->dispatcher->dispatch(PhpcrShellEvents::APPLICATION_INIT, $event);
@@ -119,7 +123,7 @@ public function init()
/**
* Register the helpers required by the application
*/
- private function registerHelpers()
+ protected function registerHelpers()
{
$phpcrHelper = new PhpcrHelper($this->transportRegistry, $this->profile);
@@ -143,7 +147,7 @@ private function registerHelpers()
/**
* Register the commands used in the shell
*/
- private function registerCommands()
+ protected function registerPhpcrCommands()
{
// phpcr commands
$this->add(new CommandPhpcr\AccessControlPrivilegeListCommand());
@@ -217,7 +221,10 @@ private function registerCommands()
$this->add(new CommandPhpcr\LockTokenListCommand());
$this->add(new CommandPhpcr\LockTokenRemoveCommand());
$this->add(new CommandPhpcr\LockUnlockCommand());
+ }
+ protected function registerShellCommands()
+ {
// add shell-specific commands
$this->add(new CommandShell\AliasListCommand());
$this->add(new CommandShell\ConfigInitCommand());
@@ -227,7 +234,7 @@ private function registerCommands()
$this->add(new CommandShell\ExitCommand());
}
- private function registerEventListeners()
+ protected function registerEventListeners()
{
$this->dispatcher->addSubscriber(new Subscriber\ProfileFromSessionInputSubscriber());
$this->dispatcher->addSubscriber(new Subscriber\ProfileWriterSubscriber(
@@ -293,7 +300,7 @@ public function doRun(InputInterface $input, OutputInterface $output)
$input = $event->getInput();
if (!$name) {
- $input = new ArrayInput(array('command' => 'shell:path:show'));
+ $input = new ArrayInput(array('command' => $this->getDefaultCommand()));
}
try {
@@ -307,6 +314,14 @@ public function doRun(InputInterface $input, OutputInterface $output)
return $exitCode;
}
+ /**
+ * Return the default command
+ */
+ protected function getDefaultCommand()
+ {
+ return 'shell:path:show';
+ }
+
/**
* Render an exception to the console
*
diff --git a/src/PHPCR/Shell/Console/Helper/ConfigHelper.php b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php
index 69e271a3..d7435e43 100644
--- a/src/PHPCR/Shell/Console/Helper/ConfigHelper.php
+++ b/src/PHPCR/Shell/Console/Helper/ConfigHelper.php
@@ -98,6 +98,11 @@ public function getConfigDir()
return $home;
}
+ private function getDistConfigDir()
+ {
+ return __DIR__ . '/../../Resources/config.dist';
+ }
+
/**
* Load the configuration
*/
@@ -106,13 +111,17 @@ public function loadConfig()
$config = array();
$configDir = $this->getConfigDir();
+ $distConfigDir = $this->getDistConfigDir();
foreach ($this->configKeys as $configKey) {
$fullPath = $configDir . '/' . $configKey . '.yml';
+ $fullDistPath = $distConfigDir . '/' . $configKey . '.yml';
$config[$configKey] = array();
if ($this->filesystem->exists($fullPath)) {
$config[$configKey] = Yaml::parse($fullPath);
+ } elseif($this->filesystem->exists($fullDistPath)) {
+ $config[$configKey] = Yaml::parse($fullDistPath);
}
}
@@ -153,7 +162,7 @@ public function initConfig(OutputInterface $output = null, DialogHelper $dialogH
}
$configDir = $this->getConfigDir();
- $distDir = __DIR__ . '/../../Resources/config.dist';
+ $distDir = $this->getDistConfigDir();
if (!$this->filesystem->exists($configDir)) {
$log('[+] Creating directory: ' . $configDir);
diff --git a/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php b/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php
index 6e6160bb..12a927de 100644
--- a/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php
+++ b/src/PHPCR/Shell/Console/Helper/PhpcrHelper.php
@@ -8,6 +8,7 @@
use PHPCR\Shell\PhpcrSession;
use PHPCR\SimpleCredentials;
use PHPCR\Shell\Transport\TransportRegistryInterface;
+use PHPCR\SessionInterface;
/**
* Helper for managing PHPCR sessions
@@ -30,13 +31,6 @@ class PhpcrHelper extends Helper
*/
protected $transportRegistry;
- /**
- * Lazy initialize PHPCR session
- *
- * @var boolean
- */
- protected $initialized = false;
-
/**
* @param TransportRegistryInterface $transportRegistry
* @param Profile $profile
@@ -57,12 +51,16 @@ public function getName()
private function init()
{
- if (false === $this->initialized) {
+ if (null === $this->session) {
$this->initSession();
- $this->initialized = true;
}
}
+ public function setSession(SessionInterface $session)
+ {
+ $this->session = $session;
+ }
+
/**
* Initialize the PHPCR session
*
diff --git a/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php b/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php
new file mode 100644
index 00000000..6d397d4b
--- /dev/null
+++ b/src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php
@@ -0,0 +1,34 @@
+
+ */
+class AutoSaveSubscriber implements EventSubscriberInterface
+{
+ public static function getSubscribedEvents()
+ {
+ return array(
+ ConsoleEvents::TERMINATE => 'handleTerminate',
+ );
+ }
+
+ public function handleTerminate(ConsoleTerminateEvent $event)
+ {
+ $command = $event->getCommand();
+ $output = $event->getOutput();
+ $session = $command->getHelper('phpcr')->getSession();
+
+ if ($session->hasPendingChanges()) {
+ $output->writeln('Auto-saving session');
+ }
+ $session->save();
+ }
+}