Skip to content
This repository has been archived by the owner on Jun 23, 2024. It is now read-only.

Commit

Permalink
Add extension points for custom variables and commands (#28)
Browse files Browse the repository at this point in the history
  • Loading branch information
lolautruche authored and theofidry committed Jul 13, 2017
1 parent c7e9bf2 commit 6c9a09b
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 45 deletions.
78 changes: 46 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ What does it do exactly?
| `$kernel` | Instance of Symfony Kernel |
| `$parameters` | Instance of Symfony parameters |

Aside from that it's the plain old [PsySH][1]! You can also [customize it](src/Resources/doc/custom.md) to add your own variables.
Aside from that it's the plain old [PsySH][1]! You can also [customize it](#customize-psysh) to add your own variables.


## Documentation
Expand Down Expand Up @@ -60,6 +60,10 @@ public function registerBundles()
## Usage

```bash
# Symfony > 3.0
php bin/console psysh

# Symfony < 3.0
php app/console psysh
```

Expand All @@ -84,51 +88,61 @@ class X

## Customize PsySH


You may also want to add a custom command or change the parameters. To achieve that, simply override the
`psysh.shell` service declaration:
### Adding a custom command
Adding a custom command for PsySH is as simple as defining a service with `psysh.command` tag!

```yaml
# app/config/config_dev.yml

services:
psysh.shell:
class: Psy\Shell
calls:
- method: setScopeVariables
arguments:
-
container: '@service_container'
session: '@session'
my_psysh_command:
class: Acme\Shell\MyCommand
tags:
- { name: psysh.command }
```
Now if you run `php app/console psysh` and then `ls`, you will see the variables `$container` and `$session`:
Or even simpler if you use Symfony 3.3+:
```yaml
services:
_defaults:
autonfigure: true
autowire: true
public: false

Acme\Shell\MyCommand: ~
```
>>> ls
Variables: $container, $session
```
The default configuration is the following:
> PsyshBundle provides autoconfiguration for custom Psysh command services, as long as they inherit from
> `Psy\Command\ReflectingCommand` or `Psy\Command\Command`.

### Adding custom variables
It is possible to add custom variables to the shell via configuration.
Variables can be of any type, container parameters references (e.g. `%kernel.debug`) or even services
(prefixed with `@`, e.g. `"@my_service"`).

```yaml
# app/config/config_dev.yml
services:
psysh.shell:
class: Psy\Shell
calls:
- method: setScopeVariables
arguments:
-
kernel: '@kernel'
container: '@service_container'
parameters: '@=service("service_container").getParameterBag().all()'
psysh:
variables:
foo: bar
router: "@router"
some: [thing, else]
debug: "%kernel.debug%"
```

Now if you run `php app/console psysh` and then `ls`, you will see the variables `$foo`, `$router`, `$some` and `$debug`,
in addition to already defined variables:

```
>>> ls
Variables: $foo, $router, $some, $debug...
```

**Note: PsyshBundle is by default registered to the Kernel only in dev/test environment and so are the bundle package.
If you override the service declaration, ensure that it will not occur in production. You can declare your service
in `app/config/config_dev.yml` for example or create a new `app/config/services_dev.yml` that will be imported only in dev.**
Default variables are:
- `$container` (the service container)
- `$kernel`
- `$parameters` (all container parameters)
- `$self` (the PsySH shell itself)


## Credits
Expand Down
12 changes: 1 addition & 11 deletions resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,8 @@
</call>
</service>

<service id="psysh.shell" class="Psy\Shell">
<service id="psysh.shell" class="Psy\Shell" public="false">
<argument type="service" id="psysh.config" />
<call method="setScopeVariables">
<argument type="collection">
<argument key="container" type="service" id="service_container" />
<argument key="kernel" type="service" id="kernel" />
<argument key="parameters" type="expression">
service('service_container').getParameterBag().all()
</argument>
<argument key="self" type="service" id="psysh.shell" />
</argument>
</call>
</service>

<service id="psysh.command.shell_command" class="Fidry\PsyshBundle\Command\PsyshCommand">
Expand Down
46 changes: 46 additions & 0 deletions src/DependencyInjection/Compiler/AddPsyshCommandPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/*
* This file is part of the PsyshBundle package.
*
* (c) Théo FIDRY <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fidry\PsyshBundle\DependencyInjection\Compiler;

use Psy\Command\Command as PsyshCommand;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* Compiler pass allowing to add Psysh commands dynamically
*
* @author Jérôme Vieilledent <[email protected]>
*
* @private
*/
final class AddPsyshCommandPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->has('psysh.shell')) {
return;
}

$commands = [];
foreach ($container->findTaggedServiceIds('psysh.command') as $id => $attributes) {
// Workaround to avoid Psysh commands to be registered as regular console commands
// (conflict with service autoconfiguration as Psysh commands inherit from \Symfony\Component\Console\Command\Command as well
// Note that this compiler pass must run with a higher priority than AddConsoleCommandPass to be efficient.
$container->findDefinition($id)->clearTag('console.command');
$commands[] = new Reference($id);
}

$shellRef = $container->findDefinition('psysh.shell');
$shellRef->addMethodCall('addCommands', [$commands]);
}
}
43 changes: 43 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

/*
* This file is part of the PsyshBundle package.
*
* (c) Théo FIDRY <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Fidry\PsyshBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
* @private
*/
final class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('psysh');

$rootNode
->children()
->arrayNode('variables')
->info('Define additional variables to be exposed in Psysh')
->useAttributeAsKey('variable_name')
->example([
'debug' => '%kernel.debug%',
'my_service' => '@my.service',
'os' => ['linux', 'macos', 'losedows'],
])
->prototype('variable')->end()
->end()
->end();

return $treeBuilder;
}
}
23 changes: 23 additions & 0 deletions src/DependencyInjection/PsyshExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@

namespace Fidry\PsyshBundle\DependencyInjection;

use Psy\Command\Command;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\ExpressionLanguage\Expression;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;

/**
Expand All @@ -32,5 +35,25 @@ public function load(array $configs, ContainerBuilder $container)
{
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__.'/../../resources/config'));
$loader->load('services.xml');

$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
foreach ($config['variables'] as $name => &$value) {
if (is_string($value) && $value[0] === '@') {
$value = new Reference(substr($value, 1));
}
}
$container->findDefinition('psysh.shell')
->addMethodCall('setScopeVariables', [$config['variables'] + [
'container' => new Reference('service_container'),
'kernel' => new Reference('kernel'),
'self' => new Reference('psysh.shell'),
'parameters' => new Expression("service('service_container').getParameterBag().all()")
]]);

// Register Psysh commands for service autoconfiguration (Symfony 3.3+)
if (method_exists($container, 'registerForAutoconfiguration')) {
$container->registerForAutoconfiguration(Command::class)->addTag('psysh.command');
}
}
}
13 changes: 11 additions & 2 deletions src/PsyshBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

namespace Fidry\PsyshBundle;

use Fidry\PsyshBundle\PsyshFacade;
use Psy\Shell;
use Fidry\PsyshBundle\DependencyInjection\Compiler\AddPsyshCommandPass;
use Psy\Command\Command;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

/**
Expand All @@ -28,4 +30,11 @@ public function boot()
$this->container->get('psysh.facade');
}

public function build(ContainerBuilder $container)
{
parent::build($container);

// Ensure that AddPsyshCommandPass runs before AddConsoleCommandPass to avoid autoconfiguration conflicts.
$container->addCompilerPass(new AddPsyshCommandPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10);
}
}

0 comments on commit 6c9a09b

Please sign in to comment.