Skip to content

[POC] Added support for embedding the shell #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 20 additions & 0 deletions spec/PHPCR/Shell/Console/Application/EmbeddedApplicationSpec.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace spec\PHPCR\Shell\Console\Application;

use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use PHPCR\Shell\Console\Application\EmbeddedApplication;

class EmbeddedApplicationSpec extends ObjectBehavior
{
function let()
{
$this->beConstructedWith(EmbeddedApplication::MODE_COMMAND);
}

function it_is_initializable()
{
$this->shouldHaveType('PHPCR\Shell\Console\Application\EmbeddedApplication');
}
}
71 changes: 71 additions & 0 deletions src/PHPCR/Shell/Console/Application/EmbeddedApplication.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace PHPCR\Shell\Console\Application;

use PHPCR\Shell\Subscriber;

/**
* Subclass of the full ShellApplication for running as an EmbeddedApplication
* (e.g. from with the DoctrinePhpcrBundle)
*
* @author Daniel Leech <daniel@dantleech.com>
*/
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());
}
}
5 changes: 1 addition & 4 deletions src/PHPCR/Shell/Console/Application/SessionApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
31 changes: 23 additions & 8 deletions src/PHPCR/Shell/Console/Application/ShellApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -101,14 +101,18 @@ 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()
{
if (true === $this->initialized) {
return;
}

$this->registerCommands();
$this->registerPhpcrCommands();
$this->registerShellCommands();

$event = new ApplicationInitEvent($this);
$this->dispatcher->dispatch(PhpcrShellEvents::APPLICATION_INIT, $event);
Expand All @@ -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);

Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand All @@ -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(
Expand Down Expand Up @@ -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 {
Expand All @@ -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
*
Expand Down
11 changes: 10 additions & 1 deletion src/PHPCR/Shell/Console/Helper/ConfigHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ public function getConfigDir()
return $home;
}

private function getDistConfigDir()
{
return __DIR__ . '/../../Resources/config.dist';
}

/**
* Load the configuration
*/
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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('<info>[+] Creating directory:</info> ' . $configDir);
Expand Down
16 changes: 7 additions & 9 deletions src/PHPCR/Shell/Console/Helper/PhpcrHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use PHPCR\Shell\PhpcrSession;
use PHPCR\SimpleCredentials;
use PHPCR\Shell\Transport\TransportRegistryInterface;
use PHPCR\SessionInterface;

/**
* Helper for managing PHPCR sessions
Expand All @@ -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
Expand All @@ -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
*
Expand Down
34 changes: 34 additions & 0 deletions src/PHPCR/Shell/Subscriber/AutoSaveSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

namespace PHPCR\Shell\Subscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Console\Event\ConsoleTerminateEvent;
use Symfony\Component\Console\ConsoleEvents;

/**
* Automatically save on console terminate event
*
* @author Daniel Leech <daniel@dantleech.com>
*/
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('<info>Auto-saving session</info>');
}
$session->save();
}
}