Skip to content

Commit

Permalink
Merge pull request #3537 from cakephp/3.0-plugin-as-themes
Browse files Browse the repository at this point in the history
3.0 plugin as themes
  • Loading branch information
lorenzo committed May 22, 2014
2 parents 711f420 + a5b83b9 commit c5f1d81
Show file tree
Hide file tree
Showing 36 changed files with 105 additions and 142 deletions.
29 changes: 3 additions & 26 deletions src/Core/App.php
Expand Up @@ -35,11 +35,10 @@
* It is also possible to inspect paths for plugin classes, for instance, to get
* the path to a plugin's helpers you would call `App::path('View/Helper', 'MyPlugin')`
*
* ### Locating plugins and themes
* ### Locating plugins
*
* Plugins and Themes can be located with App as well. Using App::pluginPath('DebugKit') for example, will
* give you the full path to the DebugKit plugin. App::themePath('purple'), would give the full path to the
* `purple` theme.
* Plugins can be located with App as well. Using App::pluginPath('DebugKit') for example, will
* give you the full path to the DebugKit plugin.
*
* ### Inspecting known objects
*
Expand Down Expand Up @@ -163,28 +162,6 @@ public static function pluginPath($plugin) {
return Plugin::path($plugin);
}

/**
* Finds the path that a theme is on. Searches through the defined theme paths.
*
* Usage:
*
* `App::themePath('MyTheme');` will return the full path to the 'MyTheme' theme.
*
* @param string $theme theme name to find the path of.
* @return string full path to the theme.
* @link http://book.cakephp.org/2.0/en/core-utility-libraries/app.html#App::themePath
*/
public static function themePath($theme) {
$themeDir = 'Themed' . DS . Inflector::camelize($theme);
$paths = static::path('Template');
foreach ($paths as $path) {
if (is_dir($path . $themeDir)) {
return $path . $themeDir . DS;
}
}
return $paths[0] . $themeDir . DS;
}

/**
* Returns the full path to a package inside the CakePHP core
*
Expand Down
8 changes: 0 additions & 8 deletions src/Routing/Filter/AssetFilter.php
Expand Up @@ -79,14 +79,6 @@ public function beforeDispatch(Event $event) {
*/
protected function _getAssetFile($url) {
$parts = explode('/', $url);
if ($parts[0] === 'theme') {
$themeName = $parts[1];
unset($parts[0], $parts[1]);
$fileFragment = implode(DS, $parts);
$path = App::themePath($themeName) . 'webroot' . DS;
return $path . $fileFragment;
}

$plugin = Inflector::camelize($parts[0]);
if ($plugin && Plugin::loaded($plugin)) {
unset($parts[0]);
Expand Down
31 changes: 11 additions & 20 deletions src/View/Helper.php
Expand Up @@ -208,24 +208,24 @@ public function url($url = null, $full = false) {
public function webroot($file) {
$asset = explode('?', $file);
$asset[1] = isset($asset[1]) ? '?' . $asset[1] : null;
$webPath = "{$this->request->webroot}" . $asset[0];
$webPath = $this->request->webroot . $asset[0];
$file = $asset[0];

if (!empty($this->theme)) {
$file = trim($file, '/');
$theme = $this->theme . '/';
$theme = Inflector::underscore($this->theme) . '/';

if (DS === '\\') {
$file = str_replace('/', '\\', $file);
}

if (file_exists(Configure::read('App.www_root') . 'theme/' . $this->theme . DS . $file)) {
$webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
if (file_exists(Configure::read('App.www_root') . $theme . $file)) {
$webPath = $this->request->webroot . $theme . $asset[0];
} else {
$themePath = App::themePath($this->theme);
$themePath = Plugin::path($this->theme);
$path = $themePath . 'webroot/' . $file;
if (file_exists($path)) {
$webPath = "{$this->request->webroot}theme/" . $theme . $asset[0];
$webPath = $this->request->webroot . $theme . $asset[0];
}
}
}
Expand Down Expand Up @@ -319,22 +319,13 @@ public function assetTimestamp($path) {
//@codingStandardsIgnoreEnd
}
$segments = explode('/', ltrim($filepath, '/'));
if ($segments[0] === 'theme') {
$theme = $segments[1];
unset($segments[0], $segments[1]);
$themePath = App::themePath($theme) . 'webroot' . DS . implode(DS, $segments);
$plugin = Inflector::camelize($segments[0]);
if (Plugin::loaded($plugin)) {
unset($segments[0]);
$pluginPath = Plugin::path($plugin) . 'webroot' . DS . implode(DS, $segments);
//@codingStandardsIgnoreStart
return $path . '?' . @filemtime($themePath);
return $path . '?' . @filemtime($pluginPath);
//@codingStandardsIgnoreEnd
} else {
$plugin = Inflector::camelize($segments[0]);
if (Plugin::loaded($plugin)) {
unset($segments[0]);
$pluginPath = Plugin::path($plugin) . 'webroot' . DS . implode(DS, $segments);
//@codingStandardsIgnoreStart
return $path . '?' . @filemtime($pluginPath);
//@codingStandardsIgnoreEnd
}
}
}
return $path;
Expand Down
25 changes: 13 additions & 12 deletions src/View/View.php
Expand Up @@ -42,10 +42,10 @@
*
* Since 2.1, the base View class also includes support for themes by default. Theme views are regular
* view files that can provide unique HTML and static assets. If theme views are not found for the
* current view the default app view files will be used. You can set `$this->theme = 'mytheme'`
* current view the default app view files will be used. You can set `$this->theme = 'Mytheme'`
* in your Controller to use the Themes.
*
* Example of theme path with `$this->theme = 'SuperHot';` Would be `app/Template/Themed/SuperHot/Posts`
* Example of theme path with `$this->theme = 'SuperHot';` Would be `Plugin/SuperHot/Template/Posts`
*
* @property \Cake\View\Helper\CacheHelper $Cache
* @property \Cake\View\Helper\FormHelper $Form
Expand Down Expand Up @@ -1096,31 +1096,32 @@ protected function _paths($plugin = null, $cached = true) {
if (!empty($plugin)) {
$count = count($viewPaths);
for ($i = 0; $i < $count; $i++) {
if (!in_array($viewPaths[$i], $corePaths)) {
$paths[] = $viewPaths[$i] . 'Plugin' . DS . $plugin . DS;
}
$paths[] = $viewPaths[$i] . 'Plugin' . DS . $plugin . DS;
}
$paths = array_merge($paths, App::path('Template', $plugin));
}

$paths = array_unique(array_merge($paths, $viewPaths));
if (!empty($this->theme)) {
$theme = Inflector::camelize($this->theme);
$themePaths = array();
foreach ($paths as $path) {
if (strpos($path, DS . 'Plugin' . DS) === false) {
if ($plugin) {
$themePaths[] = $path . 'Themed' . DS . $theme . DS . 'Plugin' . DS . $plugin . DS;
}
$themePaths[] = $path . 'Themed' . DS . $theme . DS;
$themePaths = App::path('Template', $theme);

if ($plugin) {
$count = count($viewPaths);
for ($i = 0; $i < $count; $i++) {
$themePaths[] = $themePaths[$i] . 'Plugin' . DS . $plugin . DS;
}
}

$paths = array_merge($themePaths, $paths);
}

$paths = array_merge($paths, $corePaths);

if ($plugin !== null) {
return $this->_pathsForPlugin[$plugin] = $paths;
}

return $this->_paths = $paths;
}

Expand Down
6 changes: 0 additions & 6 deletions tests/TestCase/Controller/PagesControllerTest.php
Expand Up @@ -42,12 +42,6 @@ public function testDisplay() {
$Pages->display('index');
$this->assertRegExp('/posts index/', $Pages->response->body());
$this->assertEquals('index', $Pages->viewVars['page']);

$Pages->viewPath = 'Themed';
$Pages->display('TestTheme', 'Posts', 'index');
$this->assertRegExp('/posts index themed view/', $Pages->response->body());
$this->assertEquals('TestTheme', $Pages->viewVars['page']);
$this->assertEquals('Posts', $Pages->viewVars['subpage']);
}

/**
Expand Down
15 changes: 0 additions & 15 deletions tests/TestCase/Core/AppTest.php
Expand Up @@ -248,19 +248,4 @@ public function testPluginPath() {
$this->assertPathEquals($expected, $path);
}

/**
* test that themePath can find paths for themes.
*
* @return void
*/
public function testThemePath() {
$path = App::themePath('test_theme');
$expected = TEST_APP . 'TestApp' . DS . 'Template' . DS . 'Themed' . DS . 'TestTheme' . DS;
$this->assertPathEquals($expected, $path);

$path = App::themePath('TestTheme');
$expected = TEST_APP . 'TestApp' . DS . 'Template' . DS . 'Themed' . DS . 'TestTheme' . DS;
$this->assertPathEquals($expected, $path);
}

}
6 changes: 3 additions & 3 deletions tests/TestCase/Core/PluginTest.php
Expand Up @@ -244,7 +244,7 @@ public function testPathNotFound() {
*/
public function testLoadAll() {
Plugin::loadAll();
$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo'];
$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo', 'TestTheme'];
$this->assertEquals($expected, Plugin::loaded());
}

Expand All @@ -267,7 +267,7 @@ public function testLoadAllWithPluginAlreadyLoaded() {
public function testLoadAllWithDefaults() {
$defaults = array('bootstrap' => true, 'ignoreMissing' => true);
Plugin::loadAll(array($defaults));
$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo'];
$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo', 'TestTheme'];
$this->assertEquals($expected, Plugin::loaded());
$this->assertEquals('loaded js plugin bootstrap', Configure::read('PluginTest.js_plugin.bootstrap'));
$this->assertEquals('loaded plugin bootstrap', Configure::read('PluginTest.test_plugin.bootstrap'));
Expand All @@ -287,7 +287,7 @@ public function testLoadAllWithDefaultsAndOverride() {
));
Plugin::routes();

$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo'];
$expected = ['Company', 'PluginJs', 'TestPlugin', 'TestPluginTwo', 'TestTheme'];
$this->assertEquals($expected, Plugin::loaded());
$this->assertEquals('loaded js plugin bootstrap', Configure::read('PluginTest.js_plugin.bootstrap'));
$this->assertEquals('loaded plugin routes', Configure::read('PluginTest.test_plugin.routes'));
Expand Down
7 changes: 4 additions & 3 deletions tests/TestCase/Network/Email/EmailTest.php
Expand Up @@ -1471,6 +1471,7 @@ public function testSendRenderJapanese() {
* @return void
*/
public function testSendRenderThemed() {
Plugin::load('TestTheme');
$this->CakeEmail->reset();
$this->CakeEmail->transport('debug');

Expand All @@ -1483,10 +1484,10 @@ public function testSendRenderThemed() {
$result = $this->CakeEmail->send();

$this->assertContains('In TestTheme', $result['message']);
$this->assertContains('/theme/TestTheme/img/test.jpg', $result['message']);
$this->assertContains('/test_theme/img/test.jpg', $result['message']);
$this->assertContains('Message-ID: ', $result['headers']);
$this->assertContains('To: ', $result['headers']);
$this->assertContains('/theme/TestTheme/img/test.jpg', $result['message']);
$this->assertContains('/test_theme/img/test.jpg', $result['message']);
}

/**
Expand Down Expand Up @@ -1613,7 +1614,7 @@ public function testSendRenderWithImage() {
* @return void
*/
public function testSendRenderPlugin() {
Plugin::load(['TestPlugin', 'TestPluginTwo']);
Plugin::load(['TestPlugin', 'TestPluginTwo', 'TestTheme']);

$this->CakeEmail->reset();
$this->CakeEmail->transport('debug');
Expand Down
58 changes: 39 additions & 19 deletions tests/TestCase/Routing/Filter/AssetFilterTest.php
Expand Up @@ -27,6 +27,26 @@
*/
class AssetFilterTest extends TestCase {

/**
* setUp method
*
* @return void
*/
public function setUp() {
parent::setUp();
Plugin::load(['TestTheme']);
}

/**
* tearDown method
*
* @return void
*/
public function tearDown() {
parent::tearDown();
Plugin::unload();
}

/**
* Tests that $response->checkNotModified() is called and bypasses
* file dispatching
Expand All @@ -35,11 +55,11 @@ class AssetFilterTest extends TestCase {
*/
public function testNotModified() {
$filter = new AssetFilter();
$time = filemtime(App::themePath('TestTheme') . 'webroot/img/cake.power.gif');
$time = filemtime(Plugin::path('TestTheme') . 'webroot/img/cake.power.gif');
$time = new \DateTime('@' . $time);

$response = $this->getMock('Cake\Network\Response', array('send', 'checkNotModified'));
$request = new Request('theme/test_theme/img/cake.power.gif');
$request = new Request('test_theme/img/cake.power.gif');

$response->expects($this->once())->method('checkNotModified')
->with($request)
Expand All @@ -53,7 +73,7 @@ public function testNotModified() {
$this->assertEquals($time->format('D, j M Y H:i:s') . ' GMT', $response->modified());

$response = $this->getMock('Cake\Network\Response', array('_sendHeader', 'checkNotModified'));
$request = new Request('theme/test_theme/img/cake.power.gif');
$request = new Request('test_theme/img/cake.power.gif');

$response->expects($this->once())->method('checkNotModified')
->with($request)
Expand Down Expand Up @@ -90,13 +110,13 @@ public function test404OnDoubleDot() {
$filter = new AssetFilter();

$response = $this->getMock('Response', array('_sendHeader'));
$request = new Request('theme/test_theme/../webroot/css/test_asset.css');
$request = new Request('test_theme/../webroot/css/test_asset.css');
$event = new Event('Dispatcher.beforeRequest', $this, compact('request', 'response'));

$this->assertNull($filter->beforeDispatch($event));
$this->assertFalse($event->isStopped());

$request = new Request('theme/test_theme/%3e./webroot/css/test_asset.css');
$request = new Request('test_theme/%3e./webroot/css/test_asset.css');
$event = new Event('Dispatcher.beforeRequest', $this, compact('request', 'response'));

$this->assertNull($filter->beforeDispatch($event));
Expand All @@ -116,32 +136,32 @@ public function test404OnDoubleDot() {
public static function assetProvider() {
return array(
array(
'theme/test_theme/flash/theme_test.swf',
'TestApp/Template/Themed/TestTheme/webroot/flash/theme_test.swf'
'test_theme/flash/theme_test.swf',
'Plugin/TestTheme/webroot/flash/theme_test.swf'
),
array(
'theme/test_theme/pdfs/theme_test.pdf',
'TestApp/Template/Themed/TestTheme/webroot/pdfs/theme_test.pdf'
'test_theme/pdfs/theme_test.pdf',
'Plugin/TestTheme/webroot/pdfs/theme_test.pdf'
),
array(
'theme/test_theme/img/test.jpg',
'TestApp/Template/Themed/TestTheme/webroot/img/test.jpg'
'test_theme/img/test.jpg',
'Plugin/TestTheme/webroot/img/test.jpg'
),
array(
'theme/test_theme/css/test_asset.css',
'TestApp/Template/Themed/TestTheme/webroot/css/test_asset.css'
'test_theme/css/test_asset.css',
'Plugin/TestTheme/webroot/css/test_asset.css'
),
array(
'theme/test_theme/js/theme.js',
'TestApp/Template/Themed/TestTheme/webroot/js/theme.js'
'test_theme/js/theme.js',
'Plugin/TestTheme/webroot/js/theme.js'
),
array(
'theme/test_theme/js/one/theme_one.js',
'TestApp/Template/Themed/TestTheme/webroot/js/one/theme_one.js'
'test_theme/js/one/theme_one.js',
'Plugin/TestTheme/webroot/js/one/theme_one.js'
),
array(
'theme/test_theme/space%20image.text',
'TestApp/Template/Themed/TestTheme/webroot/space image.text'
'test_theme/space%20image.text',
'Plugin/TestTheme/webroot/space image.text'
),
array(
'test_plugin/root.js',
Expand Down
1 change: 0 additions & 1 deletion tests/TestCase/Routing/Filter/CacheFilterTest.php
Expand Up @@ -68,7 +68,6 @@ public static function cacheActionProvider() {
array('TestCachedPages/test_nocache_tags'),
array('test_cached_pages/view/param/param'),
array('test_cached_pages/view?q=cakephp'),
array('test_cached_pages/themed'),
);
}

Expand Down

0 comments on commit c5f1d81

Please sign in to comment.