Skip to content

Commit

Permalink
Merge branch 'master' into 3.next
Browse files Browse the repository at this point in the history
  • Loading branch information
markstory committed Jun 25, 2018
2 parents 2fe55a5 + 6d50642 commit 6c0d566
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 66 deletions.
44 changes: 1 addition & 43 deletions src/Core/Plugin.php
Expand Up @@ -120,8 +120,6 @@ public static function load($plugin, array $config = [])
return;
}

static::_loadConfig();

$config += [
'autoload' => false,
'bootstrap' => false,
Expand All @@ -133,22 +131,7 @@ public static function load($plugin, array $config = [])
];

if (!isset($config['path'])) {
$config['path'] = Configure::read('plugins.' . $plugin);
}

if (empty($config['path'])) {
$paths = App::path('Plugin');
$pluginPath = str_replace('/', DIRECTORY_SEPARATOR, $plugin);
foreach ($paths as $path) {
if (is_dir($path . $pluginPath)) {
$config['path'] = $path . $pluginPath . DIRECTORY_SEPARATOR;
break;
}
}
}

if (empty($config['path'])) {
throw new MissingPluginException(['plugin' => $plugin]);
$config['path'] = static::getCollection()->findPath($plugin);
}

$config['classPath'] = $config['path'] . $config['classBase'] . DIRECTORY_SEPARATOR;
Expand Down Expand Up @@ -184,30 +167,6 @@ public static function load($plugin, array $config = [])
}
}

/**
* Load the plugin path configuration file.
*
* @return void
*/
protected static function _loadConfig()
{
if (Configure::check('plugins')) {
return;
}
$vendorFile = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
if (!file_exists($vendorFile)) {
$vendorFile = dirname(dirname(dirname(dirname(__DIR__)))) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
if (!file_exists($vendorFile)) {
Configure::write(['plugins' => []]);

return;
}
}

$config = require $vendorFile;
Configure::write($config);
}

/**
* Will load all the plugins located in the default plugin folder.
*
Expand All @@ -232,7 +191,6 @@ protected static function _loadConfig()
*/
public static function loadAll(array $options = [])
{
static::_loadConfig();
$plugins = [];
foreach (App::path('Plugin') as $path) {
if (!is_dir($path)) {
Expand Down
61 changes: 61 additions & 0 deletions src/Core/PluginCollection.php
Expand Up @@ -62,6 +62,67 @@ public function __construct(array $plugins = [])
foreach ($plugins as $plugin) {
$this->add($plugin);
}
$this->loadConfig();
}

/**
* Load the path information stored in vendor/cakephp-plugins.php
*
* This file is generated by the cakephp/plugin-installer package and used
* to locate plugins on the filesystem as applications can use `extra.plugin-paths`
* in their composer.json file to move plugin outside of vendor/
*
* @internal
* @return void
*/
protected function loadConfig()
{
if (Configure::check('plugins')) {
return;
}
$vendorFile = dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
if (!file_exists($vendorFile)) {
$vendorFile = dirname(dirname(dirname(dirname(__DIR__)))) . DIRECTORY_SEPARATOR . 'cakephp-plugins.php';
if (!file_exists($vendorFile)) {
Configure::write(['plugins' => []]);

return;
}
}

$config = require $vendorFile;
Configure::write($config);
}

/**
* Locate a plugin path by looking at configuration data.
*
* This will use the `plugins` Configure key, and fallback to enumerating `App::path('Plugin')`
*
* This method is not part of the official public API as plugins with
* no plugin class are being phased out.
*
* @param string $name The plugin name to locate a path for. Will return '' when a plugin cannot be found.
* @return string
* @throws Cake\Core\Exception\MissingPluginException when a plugin path cannot be resolved.
* @internal
*/
public function findPath($name)
{
$path = Configure::read('plugins.' . $name);
if ($path) {
return $path;
}

$pluginPath = str_replace('/', DIRECTORY_SEPARATOR, $name);
$paths = App::path('Plugin');
foreach ($paths as $path) {
if (is_dir($path . $pluginPath)) {
return $path . $pluginPath . DIRECTORY_SEPARATOR;
}
}

throw new MissingPluginException(['plugin' => $name]);
}

/**
Expand Down
20 changes: 12 additions & 8 deletions src/Http/BaseApplication.php
Expand Up @@ -14,6 +14,7 @@
*/
namespace Cake\Http;

use Cake\Core\App;
use Cake\Core\BasePlugin;
use Cake\Core\ConsoleApplicationInterface;
use Cake\Core\HttpApplicationInterface;
Expand Down Expand Up @@ -97,6 +98,9 @@ public function addPlugin($name, array $config = [])
} else {
$plugin = $name;
}
if (!$plugin instanceof PluginInterface) {
throw new InvalidArgumentException("The `{$name}` plugin does not implement Cake\Core\PluginInterface.");
}
$this->plugins->add($plugin);

return $this;
Expand All @@ -119,22 +123,22 @@ public function getPlugins()
* @param array $config Configuration options for the plugin
* @return \Cake\Core\PluginInterface
*/
public function makePlugin($name, array $config)
protected function makePlugin($name, array $config)
{
$className = $name;
if (strpos($className, '\\') === false) {
$className = str_replace('/', '\\', $className) . '\\' . 'Plugin';
}
if (!class_exists($className)) {
$config['name'] = $name;
$className = BasePlugin::class;
if (class_exists($className)) {
return new $className($config);
}
$plugin = new $className($config);
if (!$plugin instanceof PluginInterface) {
throw new InvalidArgumentException("The `{$name}` plugin does not implement Cake\Core\PluginInterface.");

if (!isset($config['path'])) {
$config['path'] = $this->plugins->findPath($name);
}
$config['name'] = $name;

return $plugin;
return new BasePlugin($config);
}

/**
Expand Down
26 changes: 13 additions & 13 deletions src/ORM/Table.php
Expand Up @@ -2567,17 +2567,17 @@ public function marshaller()
* ```
*
* You can limit fields that will be present in the constructed entity by
* passing the `fieldList` option, which is also accepted for associations:
* passing the `fields` option, which is also accepted for associations:
*
* ```
* $article = $this->Articles->newEntity($this->request->getData(), [
* 'fieldList' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fieldList' => 'username']]
* 'fields' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fields' => 'username']]
* ]
* );
* ```
*
* The `fieldList` option lets remove or restrict input data from ending up in
* The `fields` option lets remove or restrict input data from ending up in
* the entity. If you'd like to relax the entity's default accessible fields,
* you can use the `accessibleFields` option:
*
Expand Down Expand Up @@ -2636,12 +2636,12 @@ public function newEntity($data = null, array $options = [])
* ```
*
* You can limit fields that will be present in the constructed entities by
* passing the `fieldList` option, which is also accepted for associations:
* passing the `fields` option, which is also accepted for associations:
*
* ```
* $articles = $this->Articles->newEntities($this->request->getData(), [
* 'fieldList' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fieldList' => 'username']]
* 'fields' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fields' => 'username']]
* ]
* );
* ```
Expand All @@ -2667,12 +2667,12 @@ public function newEntities(array $data, array $options = [])
* the data merged, but those that cannot, will be discarded.
*
* You can limit fields that will be present in the merged entity by
* passing the `fieldList` option, which is also accepted for associations:
* passing the `fields` option, which is also accepted for associations:
*
* ```
* $article = $this->Articles->patchEntity($article, $this->request->getData(), [
* 'fieldList' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fieldList' => 'username']]
* 'fields' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fields' => 'username']]
* ]
* );
* ```
Expand Down Expand Up @@ -2717,12 +2717,12 @@ public function patchEntity(EntityInterface $entity, array $data, array $options
* the data merged, but those that cannot, will be discarded.
*
* You can limit fields that will be present in the merged entities by
* passing the `fieldList` option, which is also accepted for associations:
* passing the `fields` option, which is also accepted for associations:
*
* ```
* $articles = $this->Articles->patchEntities($articles, $this->request->getData(), [
* 'fieldList' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fieldList' => 'username']]
* 'fields' => ['title', 'body', 'tags', 'comments'],
* 'associated' => ['Tags', 'Comments.Users' => ['fields' => 'username']]
* ]
* );
* ```
Expand Down
28 changes: 28 additions & 0 deletions tests/TestCase/Core/PluginCollectionTest.php
Expand Up @@ -13,6 +13,7 @@
*/
namespace Cake\Test\TestCase\Core;

use Cake\Core\Configure;
use Cake\Core\Exception\MissingPluginException;
use Cake\Core\PluginCollection;
use Cake\Core\PluginInterface;
Expand Down Expand Up @@ -137,4 +138,31 @@ public function testWithInvalidHook()
foreach ($plugins->with('bad') as $p) {
}
}

public function testFindPathNoConfigureData()
{
Configure::write('plugins', []);
$plugins = new PluginCollection();
$path = $plugins->findPath('TestPlugin');

$this->assertEquals(TEST_APP . 'Plugin' . DS . 'TestPlugin' . DS, $path);
}

public function testFindPathConfigureData()
{
Configure::write('plugins', ['TestPlugin' => '/some/path']);
$plugins = new PluginCollection();
$path = $plugins->findPath('TestPlugin');

$this->assertEquals('/some/path', $path);
}

public function testFindPathMissingPlugin()
{
Configure::write('plugins', []);
$plugins = new PluginCollection();

$this->expectException(MissingPluginException::class);
$plugins->findPath('InvalidPlugin');
}
}
17 changes: 15 additions & 2 deletions tests/TestCase/Http/BaseApplicationTest.php
Expand Up @@ -84,9 +84,22 @@ public function testInvoke()
public function testAddPluginUnknownClass()
{
$app = $this->getMockForAbstractClass(BaseApplication::class, [$this->path]);
$app->addPlugin('SomethingBad');
$plugin = $app->getPlugins()->get('SomethingBad');
$app->addPlugin('PluginJs');
$plugin = $app->getPlugins()->get('PluginJs');
$this->assertInstanceOf(BasePlugin::class, $plugin);

$this->assertEquals(
TEST_APP . 'Plugin' . DS . 'PluginJs' . DS,
$plugin->getPath()
);
$this->assertEquals(
TEST_APP . 'Plugin' . DS . 'PluginJs' . DS . 'config' . DS,
$plugin->getConfigPath()
);
$this->assertEquals(
TEST_APP . 'Plugin' . DS . 'PluginJs' . DS . 'src' . DS,
$plugin->getClassPath()
);
}

/**
Expand Down

0 comments on commit 6c0d566

Please sign in to comment.