Skip to content

Commit

Permalink
Merge pull request #32 from beporter/fix-deprecations
Browse files Browse the repository at this point in the history
Update Shell for Cake 3.6 compatibility.
  • Loading branch information
kriskd authored Oct 22, 2018
2 parents c8a67d3 + 38e611d commit 7a4a69d
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 81 deletions.
10 changes: 4 additions & 6 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ language: php
sudo: false

php:
- 5.6
- 7.2

# Environment Variables to set
env:
global:
# Contains a $GITHUB_TOKEN env var for use with composer to avoid API limits.
- secure: "JPIIdecDmF2AsgH3b5QWYzr2TunB4tpIBl0/64EGsWZ+5A85Co3NN+eSshgWI5vOjaaJji/S2rKwMRvV9h/YceTL/UH5D2xd/HobRpHAaJSyjp5cplQawokzR/+PrikjmbwTZdeiIaHpUMCqbQvV2+Jq+Vx5vD28+hya1yTdQsk="


# Cache the composer directories, only allowed if using the container based setup
# which depends on setting sudo to false
cache:
Expand All @@ -29,8 +28,7 @@ before_install:
- mkdir -p build/logs

install:
- composer config -g github-oauth.github.com $GITHUB_TOKEN
- composer install --no-interaction
- composer install --dev --no-interaction

before_script:
- phpenv rehash
Expand All @@ -40,8 +38,8 @@ script:
- vendor/bin/phpcs -np --extensions=php --standard=Loadsys ./src ./tests
- vendor/bin/phpunit --coverage-clover=build/logs/clover.xml

after_script:
- php vendor/bin/coveralls -v
after_success:
- travis_retry php vendor/bin/php-coveralls -v

notifications:
email: false
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# The MIT License (MIT)

Copyright (c) 2015 Loadsys Web Strategies
Copyright (c) 2018 Loadsys Web Strategies

> Permission is hereby granted, free of charge, to any person obtaining a copy
> of this software and associated documentation files (the "Software"), to deal
Expand Down
49 changes: 28 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,29 @@

A CakePHP plugin that provides a Shell to read an app's Configure vars from the command line.

* This is the Cake 3.x version of the plugin, which exists on the `master` branch and is tracked by the `~3.0` semver.
* For the Cake 2.x version of this plugin, please use the repo's `cake-2.x` branch. (semver `~2.0`)
* For the Cake 1.3 version, use the `cake-1.3` branch. (semver `~1.0`) **Note:** we don't expect to actively maintain or improve the 1.3 version. It's here because the project started life as a 1.3 Shell.
## Installation
Use the following as a guide for choosing your version based on the version of CakePHP installed.

| CakePHP | ConfigReadShell Plugin | Tag | Notes |
| :-------------: | :------------------------: | :--: | :---- |
| ^3.4 | [master](https://github.com/loadsys/CakePHP-ConfigReadShell/tree/master) | 4.0.0 | stable |
| 3.3 | [3.3](https://github.com/loadsys/CakePHP-ConfigReadShell/tree/3.0.0) | 3.0.0 | stable |
| 2.5 | [2.x](https://github.com/loadsys/CakePHP-ConfigReadShell/tree/2.0.1) | 2.0.1 | stable |
| 1.3 | [1.x](https://github.com/loadsys/CakePHP-ConfigReadShell/tree/1.0.1) | 1.0.1 | stable |

## Requirements

* CakePHP 3.1.0+
* PHP 5.6+
### This will install the latest version.
```bash
$ composer require loadsys/cakephp-config-read:~4.0
```

**Note:** we don't expect to actively maintain or improve the 1.3 version. It's here because the project started life as a 1.3 Shell.

## Installation
## Requirements

* PHP 7.0+
* CakePHP 3.6.0+

```bash
$ composer require loadsys/cakephp-config-read:~3.0
```


## Usage
Expand Down Expand Up @@ -105,19 +112,19 @@ Array

CakePHP 3 by default "consumes" some of its configs so as not to confuse developers. [`Configure::consume()`](http://book.cakephp.org/3.0/en/development/configuration.html#Cake\Core\Configure::consume) removes the configuration key from Configure, making it unavailable to the rest of the app. At the [time of this writing](https://github.com/cakephp/app/blob/a0f2c4/config/bootstrap.php#L136,L141), it does this for the following keys/classes:

| _`[Configure.Key]`_ | _`Class::configEnumerationMethod()`_ | _`Class::configFetchMethod()`_ |
|----------------------|---------------------------------------|---------------------------------|
| `[Cache]` | `Cache::configured()` | `Cache::config()` |
| `[Datasources]` | `ConnectionManager::configured()` | `ConnectionManager::config()` |
| `[EmailTransport]` | `Email::configuredTransport()` | `Email::configTransport()` |
| `[Email]` | `Email::configured()` | `Email::config()` |
| `[Log]` | `Log::configured()` | `Log::config()` |
| `[Security.salt]` | _(none)_ | `Security::salt()` |
| _`[Configure.Key]`_ | _`Class::configEnumerationMethod()`_ | _`Class::configFetchMethod()`_ |
|----------------------|---------------------------------------|-----------------------------------|
| `[Cache]` | `Cache::configured()` | `Cache::getConfig()` |
| `[Datasources]` | `ConnectionManager::configured()` | `ConnectionManager::getConfig()` |
| `[EmailTransport]` | `Email::configuredTransport()` | `Email::getConfigTransport()` |
| `[Email]` | `Email::configured()` | `Email::getConfig()` |
| `[Log]` | `Log::configured()` | `Log::getConfig()` |
| `[Security.salt]` | _(none)_ | `Security::getSalt()` |


The ConfigReadShell devotes about half of its codebase dealing with this for you, allowing you to continue to fetch values using the Configure path (`Datasources.default.host` -> `localhost`) while in the background it is actually querying `ConnectionManager::config('default')['host']`. (This is particularly helpful if you are using [Environment-Aware Configs](https://github.com/beporter/CakePHP-EnvAwareness/tree/master/slides).)
The ConfigReadShell devotes about half of its codebase dealing with this for you, allowing you to continue to fetch values using the Configure path (`Datasources.default.host` -> `localhost`) while in the background it is actually querying `ConnectionManager::getConfig('default')['host']`. (This is particularly helpful if you are using [Environment-Aware Configs](https://github.com/beporter/CakePHP-EnvAwareness/tree/master/slides).)

The "gotcha" here is that ConfigReadShell has to maintain a hard-coded list of Configure keys that are normally consumed, and how to access them in their new container. This is further complicated by the fact that not all consumed configs are loaded into or retrieved from their containers the same way, although the base assumption is that the container implements the [`StaticConfigTrait`](http://api.cakephp.org/3.0/class-Cake.Core.StaticConfigTrait.html) and so will have `::config()` and `::configured()` available.
The "gotcha" here is that ConfigReadShell has to maintain a hard-coded list of Configure keys that are normally consumed, and how to access them in their new container. This is further complicated by the fact that not all consumed configs are loaded into or retrieved from their containers the same way, although the base assumption is that the container implements the [`StaticConfigTrait`](http://api.cakephp.org/3.0/class-Cake.Core.StaticConfigTrait.html) and so will have `::getConfig()` and `::configured()` available.

:warning: **If your app uses `Configure::consume()` on any non-standard Configure key during bootstrapping, you will not be able to obtain any child values of those keys from the ConfigReadShell.**

Expand All @@ -143,4 +150,4 @@ When developing this plugin, please fork and issue a PR for any new development.

## Copyright

[Loadsys Web Strategies](http://www.loadsys.com) 2016
[Loadsys Web Strategies](http://www.loadsys.com) 2018
8 changes: 4 additions & 4 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
"source": "https://github.com/loadsys/CakePHP-ConfigReadShell"
},
"require": {
"php": ">=5.4",
"cakephp/cakephp": "~3.1",
"php": ">=7.0",
"cakephp/cakephp": "^3.4",
"composer/installers": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.1",
"phpunit/phpunit": "~6.0",
"loadsys/loadsys_codesniffer": "dev-master",
"satooshi/php-coveralls": "dev-master"
"php-coveralls/php-coveralls": "^2.0"
},
"autoload": {
"psr-4": {
Expand Down
10 changes: 3 additions & 7 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,9 @@

<!-- Prevent coverage reports from looking in tests and vendors -->
<filter>
<blacklist>
<directory suffix=".php">./vendor/</directory>
<directory suffix=".ctp">./vendor/</directory>

<directory suffix=".php">./tests/</directory>
<directory suffix=".ctp">./tests/</directory>
</blacklist>
<whitelist>
<directory suffix=".php">./src/</directory>
</whitelist>
</filter>

</phpunit>
52 changes: 26 additions & 26 deletions src/Shell/ConfigReadShell.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,29 @@ class ConfigReadShell extends Shell {
* Cake 3 uses Configure::consume() on a number of Configure keys to
* prime different Cake modules in `config/boostrap.php`.
*
* Cache::config(Configure::consume('Cache'));
* ConnectionManager::config(Configure::consume('Datasources'));
* Email::configTransport(Configure::consume('EmailTransport'));
* Email::config(Configure::consume('Email'));
* Log::config(Configure::consume('Log'));
* Security::salt(Configure::consume('Security.salt'));
* Cache::setConfig(Configure::consume('Cache'));
* ConnectionManager::setConfig(Configure::consume('Datasources'));
* Email::setConfigTransport(Configure::consume('EmailTransport'));
* Email::setConfig(Configure::consume('Email'));
* Log::setConfig(Configure::consume('Log'));
* Security::setSalt(Configure::consume('Security.salt'));
*
* This removes the configs from Configure, making them inaccessible
* through standard means in this Shell.
*
* This property tracks specific key names and the class::method they
* map to so we can perform the correct logic to fetch the values. For
* example, a request for `Cache._cake_core_.className` would result
* in a call like `\Cake\Cache\Cache::config('_cake_core_')['className']`.
* in a call like `\Cake\Cache\Cache::getConfig('_cake_core_')['className']`.
*
* @var array
*/
public $specialKeys = [
'Cache' => '\Cake\Cache\Cache::config',
'Datasources' => '\Cake\Datasource\ConnectionManager::config',
'EmailTransport' => '\Cake\Mailer\Email::configTransport',
'Email' => '\Cake\Mailer\Email::config',
'Log' => '\Cake\Log\Log::config',
'Cache' => '\Cake\Cache\Cache::getConfig',
'Datasources' => '\Cake\Datasource\ConnectionManager::getConfig',
'EmailTransport' => '\Cake\Mailer\Email::getConfigTransport',
'Email' => '\Cake\Mailer\Email::getConfig',
'Log' => '\Cake\Log\Log::getConfig',
'Security.salt' => 'self::securitySaltHelper',
];

Expand All @@ -96,11 +96,11 @@ public function startup() {

if (empty($this->args)) {
$this->_displayHelp('');
$this->error(__('No Configure keys provided.'));
$this->abort(__('No Configure keys provided.'));
}

// All other output should not be processed by the Shell.
$this->_io->outputAs(ConsoleOutput::RAW);
$this->_io->setOutputAs(ConsoleOutput::RAW);
}

/**
Expand Down Expand Up @@ -262,16 +262,16 @@ protected function specialKey($search) {
* There are three cases to handle:
*
* 1. A "deep" subkey like `Cache.default.className`. In this case,
* we need to fetch `Cache::config('default')` and then return
* we need to fetch `Cache::getConfig('default')` and then return
* the ['className'] from the result.
*
* 2. A single config array like `Cache.default. We need to fetch
* `Cache::config('default')` and return the whole thing.
* `Cache::getConfig('default')` and return the whole thing.
*
* 3. All configs in a module like `Cache`. In this case we need to
* try calling `Cache::configured()` (if it exists), then looping
* over the results using each as a key name for a separate call
* to `Cache::config($name)` and accumulating all of the results
* to `Cache::getConfig($name)` and accumulating all of the results
* together to return.
*
* @param array $special An array containing at least a [callable] key and possibly [arg] and [subkey]s.
Expand All @@ -282,7 +282,7 @@ protected function fetchSpecial($special) {
$set = call_user_func($special['callable'], $special['arg']);
} else {
$allConfigCallable = str_replace(
'::config',
'::getConfig',
'::configured',
$special['callable'],
$replaceCount
Expand Down Expand Up @@ -362,20 +362,20 @@ protected function printVal($key, $val) {
/**
* Provides a custom helper for fetching the App's Security.salt value.
*
* The call to Security::salt() method requires no arguments to get the
* The call to Security::getSalt() method requires no arguments to get the
* current value but we will have split the command line request for
* `Security.salt` into
* `call_user_func('\Cake\Utility\Security::salt', 'salt'). That will
* `call_user_func('\Cake\Utility\Security::getSalt', 'salt'). That will
* **set** the salt to `salt` and return "salt" as the new value, which
* isn't what we want. This method exists to be the callable function,
* which itself passes the proper `null` value as the argument, which
* in turn will return the _actual_ salt value.
* which itself passes no arguments to getSalt, which in turn will return
* the _actual_ salt value.
*
* @param string $salt Because of how this is implemented, this will always be the literal string "salt" and will be ignored.
@return string The result of calling `Security::salt(null);`
* @return string The result of calling `Security::getSalt();`
*/
private function securitySaltHelper($salt) {
return call_user_func('\Cake\Utility\Security::salt', null);
return call_user_func('\Cake\Utility\Security::getSalt');
}

/**
Expand All @@ -402,10 +402,10 @@ public function getOptionParser() {
'default' => false,
'help' => __('Encode all output using PHP\'s `serialize()` method. Makes the Shell\'s output suitable for consumption by other PHP console scripts. Always overrides the --bash option. A single requested key will be serialized directly. Multiple requested keys will be combined into an associative array with the provided arguments as key names and then serialized.'),
])
->description(
->setDescription(
__('Provides CLI access to variables defined in the Configure class of the host CakePHP application. Will output the value of any keys passed as arguments. Equivelant to `Configure::read(\'Key.Name\')`. Unrecognized keys will produce empty string or `null` output.')
)
->epilog(
->setEpilog(
__('Provide the Key.name(s) to fetch from Configure::read() as arguments. Multiple keys may be specified, separated by spaces.')
);

Expand Down
Empty file removed tests/Fixture/.gitkeep
Empty file.
32 changes: 17 additions & 15 deletions tests/TestCase/Shell/ConfigReadShellTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,10 @@ class ConfigReadShellTest extends TestCase {
*/
public static function setUpBeforeClass() {
// Prime the ConnectionManager with some configs.
ConnectionManager::config(self::$datasources);
ConnectionManager::setConfig(self::$datasources);

// Prime the security salt.
Security::salt(self::$salt);
Security::setSalt(self::$salt);
}

/**
Expand All @@ -104,7 +104,7 @@ public static function tearDownAfterClass() {
ConnectionManager::drop($ds);
}

Security::salt('');
Security::setSalt('');
}

/**
Expand Down Expand Up @@ -203,29 +203,32 @@ protected function getSUTClassName() {
*/
protected function initSUT($additionalMocks = []) {
$defaultMocks = [
'_displayHelp', 'error',
'_displayHelp', 'abort',
];

$this->io = $this->getMock('\Cake\Console\ConsoleIo', [], [], '', false);
$this->io = $this->getMockBuilder('\Cake\Console\ConsoleIo')
->disableOriginalConstructor()
->getMock();
$this->io->expects($this->any())
->method('out')
->with($this->anything())
->will($this->returnCallback([$this, 'outputCollector']));


$class = $this->getSUTClassName();
$mockedMethods = array_merge($defaultMocks, $additionalMocks);
$shell = $this->getMock(
$class,
$mockedMethods,
[$this->io]
);
$shell = $this->getMockBuilder($class)
->setMethods($mockedMethods)
->setConstructorArgs([$this->io])
->getMock();

$shell->expects($this->any())
->method('error')
->method('abort')
->with($this->anything())
->will($this->returnCallback([$this, 'outputCollector']));
$shell->OptionParser = $this->getMock('\Cake\Console\ConsoleOptionParser', [], [null, false]);
$shell->OptionParser = $this->getMockBuilder('\Cake\Console\ConsoleOptionParser')
->setMethods([])
->setConstructorArgs([null, false])
->getMock();
$shell->params = [
'help' => false,
'verbose' => false,
Expand Down Expand Up @@ -253,7 +256,7 @@ public function testStartupHelp() {
$this->Shell->expects($this->once())
->method('_displayHelp');

Cache::config('_cake_core_', [
Cache::setConfig('_cake_core_', [
'className' => 'File',
]);
$this->Shell->startup();
Expand Down Expand Up @@ -482,7 +485,6 @@ public function provideSerializedArgs() {
];
}


/**
* test main(), requesting "special" config keys.
*
Expand Down
2 changes: 1 addition & 1 deletion tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
if (!getenv('db_dsn')) {
putenv('db_dsn=sqlite:///:memory:');
}
ConnectionManager::config('test', ['url' => getenv('db_dsn')]);
ConnectionManager::setConfig('test', ['url' => getenv('db_dsn')]);

Plugin::load('ConfigReadShell', [
'path' => dirname(dirname(__FILE__)) . DS,
Expand Down

0 comments on commit 7a4a69d

Please sign in to comment.