Skip to content

Commit

Permalink
Update App::classname for more flexiblity
Browse files Browse the repository at this point in the history
Allow using `/` within a classname, previously the following would fail:

    App::classname('Some/Class', 'Namespace');

Even if `App\Namespace\Some\Class.php exists
  • Loading branch information
AD7six committed Dec 8, 2013
1 parent 1b6f948 commit c55debb
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 29 deletions.
21 changes: 17 additions & 4 deletions Cake/Core/App.php
Expand Up @@ -89,20 +89,33 @@ public static function classname($class, $type = '', $suffix = '') {
}
$base = rtrim($base, '\\');

$fullname = '\\' . str_replace('/', '\\', $type) . '\\' . $name . $suffix;
if (class_exists($base . $fullname)) {
$fullname = '\\' . str_replace('/', '\\', $type . '\\' . $name) . $suffix;

if (static::_classExistsInBase($fullname, $base)) {
return $base . $fullname;
}
if ($plugin) {
return false;
}

if (class_exists('Cake' . $fullname)) {
if (static::_classExistsInBase($fullname, 'Cake')) {
return 'Cake' . $fullname;
}
return false;
}

/**
* _classExistsInBase
*
* Test isolation wrapper
*
* @param string $name
* @param string $namespace
* @return bool
*/
protected static function _classExistsInBase($name, $namespace) {
return class_exists($namespace . $name);
}

/**
* Used to read information stored path
*
Expand Down
91 changes: 66 additions & 25 deletions Cake/Test/TestCase/Core/AppTest.php
Expand Up @@ -37,36 +37,77 @@ public function tearDown() {
}

/**
* testClassname method
* testClassname
*
* $checkCake and $existsInCake are derived from the input parameters
*
* @dataProvider classnameProvider
* @return void
*/
public function testClassname() {
public function testClassname($class, $type, $suffix = '', $existsInBase = false, $expected = false) {
Configure::write('App.namespace', 'TestApp');
$mock = $this->getMockClass('Cake\Core\App', ['_classExistsInBase']);

$mock::staticExpects($this->at(0))
->method('_classExistsInBase')
->will($this->returnValue($existsInBase));

$checkCake = (!$existsInBase || strpos('.', $class));
if ($checkCake) {
$existsInCake = (bool)$expected;
$mock::staticExpects($this->at(1))
->method('_classExistsInBase')
->will($this->returnValue($existsInCake));
}

$return = $mock::classname($class, $type, $suffix);
$this->assertSame($expected, $return);
}

// Test core
$this->assertEquals('Cake\Core\App', App::classname('App', 'Core'));
$this->assertFalse(App::classname('App', 'Core', 'Suffix'));

// Assert prefix
$this->assertFalse(App::classname('Auth', 'Controller/Component'));
$this->assertEquals('Cake\Controller\Component\AuthComponent', App::classname('Auth', 'Controller/Component', 'Component'));

// Test app
$this->assertEquals('TestApp\Controller\PagesController', App::classname('Pages', 'Controller', 'Controller'));
$this->assertFalse(App::classname('Unknown', 'Controller', 'Controller'));

// Test plugin
Plugin::load('TestPlugin');
$this->assertEquals('TestPlugin\Utility\TestPluginEngine', App::classname('TestPlugin.TestPlugin', 'Utility', 'Engine'));
$this->assertFalse(App::classname('TestPlugin.Unknown', 'Utility'));

$this->assertFalse(Plugin::loaded('TestPluginTwo'), 'TestPluginTwo should not be loaded.');
// Test unknown plugin
$this->assertEquals(
'TestPluginTwo\Console\Command\ExampleShell',
App::classname('TestPluginTwo.Example', 'Console/Command', 'Shell')
);
/**
* classnameProvider
*
* Return test permutations for testClassname method. Format:
* classname
* type
* suffix
* existsInBase (Base meaning App or plugin namespace)
* expected return value
*
* @return void
*/
public function classnameProvider() {
return [
['Does', 'Not', 'Exist'],

['Exists', 'In', 'App', true, 'TestApp\In\ExistsApp'],
['Also/Exists', 'In', 'App', true, 'TestApp\In\Also\ExistsApp'],
['Also', 'Exists/In', 'App', true, 'TestApp\Exists\In\AlsoApp'],
['Also', 'Exists/In/Subfolder', 'App', true, 'TestApp\Exists\In\Subfolder\AlsoApp'],

['MyPlugin.Exists', 'In', 'Suffix', true, 'MyPlugin\In\ExistsSuffix'],
['MyPlugin.Also/Exists', 'In', 'Suffix', true, 'MyPlugin\In\Also\ExistsSuffix'],
['MyPlugin.Also', 'Exists/In', 'Suffix', true, 'MyPlugin\Exists\In\AlsoSuffix'],
['MyPlugin.Also', 'Exists/In/Subfolder', 'Suffix', true, 'MyPlugin\Exists\In\Subfolder\AlsoSuffix'],

['Exists', 'In', 'Cake', false, 'Cake\In\ExistsCake'],
['Also/Exists', 'In', 'Cake', false, 'Cake\In\Also\ExistsCake'],
['Also', 'Exists/In', 'Cake', false, 'Cake\Exists\In\AlsoCake'],
['Also', 'Exists/In/Subfolder', 'Cake', false, 'Cake\Exists\In\Subfolder\AlsoCake'],

// Realistic examples returning nothing
['App', 'Core', 'Suffix'],
['Auth', 'Controller/Component'],
['Unknown', 'Controller', 'Controller'],

// Real examples returning classnames
['App', 'Core', '', false, 'Cake\Core\App'],
['Auth', 'Controller/Component', 'Component', false, 'Cake\Controller\Component\AuthComponent'],
['File', 'Cache/Engine', 'Engine', false, 'Cake\Cache\Engine\FileEngine'],
['Command', 'Console/Command/Task', 'Task', false, 'Cake\Console\Command\Task\CommandTask'],
['Upgrade/Locations', 'Console/Command/Task', 'Task', false, 'Cake\Console\Command\Task\Upgrade\LocationsTask'],
['Pages', 'Controller', 'Controller', true, 'TestApp\Controller\PagesController'],
];
}

/**
Expand Down

0 comments on commit c55debb

Please sign in to comment.