SchemaShellTest.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621
  1. <?php
  2. /**
  3. * SchemaShellTest Test file
  4. *
  5. * PHP 5
  6. *
  7. * CakePHP : Rapid Development Framework (http://cakephp.org)
  8. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  9. *
  10. * Licensed under The MIT License
  11. * For full copyright and license information, please see the LICENSE.txt
  12. * Redistributions of files must retain the above copyright notice.
  13. *
  14. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  15. * @link http://cakephp.org CakePHP Project
  16. * @package Cake.Test.Case.Console.Command
  17. * @since CakePHP v 1.3
  18. * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  19. */
  20. App::uses('ShellDispatcher', 'Console');
  21. App::uses('ConsoleOutput', 'Console');
  22. App::uses('ConsoleInput', 'Console');
  23. App::uses('Shell', 'Console');
  24. App::uses('CakeSchema', 'Model');
  25. App::uses('SchemaShell', 'Console/Command');
  26. /**
  27. * Test for Schema database management
  28. *
  29. * @package Cake.Test.Case.Console.Command
  30. */
  31. class SchemaShellTestSchema extends CakeSchema {
  32. /**
  33. * name property
  34. *
  35. * @var string 'MyApp'
  36. */
  37. public $name = 'SchemaShellTest';
  38. /**
  39. * connection property
  40. *
  41. * @var string 'test'
  42. */
  43. public $connection = 'test';
  44. /**
  45. * comments property
  46. *
  47. * @var array
  48. */
  49. public $comments = array(
  50. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  51. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  52. 'user_id' => array('type' => 'integer', 'null' => false),
  53. 'title' => array('type' => 'string', 'null' => false, 'length' => 100),
  54. 'comment' => array('type' => 'text', 'null' => false, 'default' => null),
  55. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  56. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  57. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  58. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  59. );
  60. /**
  61. * posts property
  62. *
  63. * @var array
  64. */
  65. public $articles = array(
  66. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  67. 'user_id' => array('type' => 'integer', 'null' => true, 'default' => ''),
  68. 'title' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
  69. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  70. 'summary' => array('type' => 'text', 'null' => true),
  71. 'published' => array('type' => 'string', 'null' => true, 'default' => 'Y', 'length' => 1),
  72. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  73. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  74. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  75. );
  76. public $newone = array(
  77. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  78. 'testit' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
  79. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  80. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  81. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  82. );
  83. }
  84. /**
  85. * SchemaShellTest class
  86. *
  87. * @package Cake.Test.Case.Console.Command
  88. */
  89. class SchemaShellTest extends CakeTestCase {
  90. /**
  91. * Fixtures
  92. *
  93. * @var array
  94. */
  95. public $fixtures = array(
  96. 'core.article', 'core.user', 'core.post', 'core.auth_user', 'core.author',
  97. 'core.comment', 'core.test_plugin_comment', 'core.aco', 'core.aro', 'core.aros_aco',
  98. );
  99. /**
  100. * setUp method
  101. *
  102. * @return void
  103. */
  104. public function setUp() {
  105. parent::setUp();
  106. $out = $this->getMock('ConsoleOutput', array(), array(), '', false);
  107. $in = $this->getMock('ConsoleInput', array(), array(), '', false);
  108. $this->Shell = $this->getMock(
  109. 'SchemaShell',
  110. array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop'),
  111. array($out, $out, $in)
  112. );
  113. }
  114. /**
  115. * tearDown method
  116. *
  117. * @return void
  118. */
  119. public function tearDown() {
  120. parent::tearDown();
  121. if (!empty($this->file) && $this->file instanceof File) {
  122. $this->file->delete();
  123. unset($this->file);
  124. }
  125. }
  126. /**
  127. * test startup method
  128. *
  129. * @return void
  130. */
  131. public function testStartup() {
  132. $this->Shell->startup();
  133. $this->assertTrue(isset($this->Shell->Schema));
  134. $this->assertTrue(is_a($this->Shell->Schema, 'CakeSchema'));
  135. $this->assertEquals(Inflector::camelize(Inflector::slug(APP_DIR)), $this->Shell->Schema->name);
  136. $this->assertEquals('schema.php', $this->Shell->Schema->file);
  137. $this->Shell->Schema = null;
  138. $this->Shell->params = array(
  139. 'name' => 'TestSchema'
  140. );
  141. $this->Shell->startup();
  142. $this->assertEquals('TestSchema', $this->Shell->Schema->name);
  143. $this->assertEquals('test_schema.php', $this->Shell->Schema->file);
  144. $this->assertEquals('default', $this->Shell->Schema->connection);
  145. $this->assertEquals(APP . 'Config' . DS . 'Schema', $this->Shell->Schema->path);
  146. $this->Shell->Schema = null;
  147. $this->Shell->params = array(
  148. 'file' => 'other_file.php',
  149. 'connection' => 'test',
  150. 'path' => '/test/path'
  151. );
  152. $this->Shell->startup();
  153. $this->assertEquals(Inflector::camelize(Inflector::slug(APP_DIR)), $this->Shell->Schema->name);
  154. $this->assertEquals('other_file.php', $this->Shell->Schema->file);
  155. $this->assertEquals('test', $this->Shell->Schema->connection);
  156. $this->assertEquals('/test/path', $this->Shell->Schema->path);
  157. }
  158. /**
  159. * Test View - and that it dumps the schema file to stdout
  160. *
  161. * @return void
  162. */
  163. public function testView() {
  164. $this->Shell->startup();
  165. $this->Shell->Schema->path = APP . 'Config' . DS . 'Schema';
  166. $this->Shell->params['file'] = 'i18n.php';
  167. $this->Shell->expects($this->once())->method('_stop');
  168. $this->Shell->expects($this->once())->method('out');
  169. $this->Shell->view();
  170. }
  171. /**
  172. * test that view() can find plugin schema files.
  173. *
  174. * @return void
  175. */
  176. public function testViewWithPlugins() {
  177. App::build(array(
  178. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  179. ));
  180. CakePlugin::load('TestPlugin');
  181. $this->Shell->args = array('TestPlugin.schema');
  182. $this->Shell->startup();
  183. $this->Shell->expects($this->exactly(2))->method('_stop');
  184. $this->Shell->expects($this->atLeastOnce())->method('out');
  185. $this->Shell->view();
  186. $this->Shell->args = array();
  187. $this->Shell->params = array('plugin' => 'TestPlugin');
  188. $this->Shell->startup();
  189. $this->Shell->view();
  190. App::build();
  191. CakePlugin::unload();
  192. }
  193. /**
  194. * test dump() with sql file generation
  195. *
  196. * @return void
  197. */
  198. public function testDumpWithFileWriting() {
  199. $this->Shell->params = array(
  200. 'name' => 'i18n',
  201. 'connection' => 'test',
  202. 'write' => TMP . 'tests' . DS . 'i18n.sql'
  203. );
  204. $this->Shell->expects($this->once())->method('_stop');
  205. $this->Shell->startup();
  206. $this->Shell->dump();
  207. $this->file = new File(TMP . 'tests' . DS . 'i18n.sql');
  208. $contents = $this->file->read();
  209. $this->assertRegExp('/DROP TABLE/', $contents);
  210. $this->assertRegExp('/CREATE TABLE.*?i18n/', $contents);
  211. $this->assertRegExp('/id/', $contents);
  212. $this->assertRegExp('/model/', $contents);
  213. $this->assertRegExp('/field/', $contents);
  214. $this->assertRegExp('/locale/', $contents);
  215. $this->assertRegExp('/foreign_key/', $contents);
  216. $this->assertRegExp('/content/', $contents);
  217. }
  218. /**
  219. * test that dump() can find and work with plugin schema files.
  220. *
  221. * @return void
  222. */
  223. public function testDumpFileWritingWithPlugins() {
  224. App::build(array(
  225. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  226. ));
  227. CakePlugin::load('TestPlugin');
  228. $this->Shell->args = array('TestPlugin.TestPluginApp');
  229. $this->Shell->params = array(
  230. 'connection' => 'test',
  231. 'write' => TMP . 'tests' . DS . 'dump_test.sql'
  232. );
  233. $this->Shell->startup();
  234. $this->Shell->expects($this->once())->method('_stop');
  235. $this->Shell->dump();
  236. $this->file = new File(TMP . 'tests' . DS . 'dump_test.sql');
  237. $contents = $this->file->read();
  238. $this->assertRegExp('/CREATE TABLE.*?test_plugin_acos/', $contents);
  239. $this->assertRegExp('/id/', $contents);
  240. $this->assertRegExp('/model/', $contents);
  241. $this->file->delete();
  242. App::build();
  243. CakePlugin::unload();
  244. }
  245. /**
  246. * test generate with snapshot generation
  247. *
  248. * @return void
  249. */
  250. public function testGenerateSnapshot() {
  251. $this->Shell->path = TMP;
  252. $this->Shell->params['file'] = 'schema.php';
  253. $this->Shell->params['force'] = false;
  254. $this->Shell->args = array('snapshot');
  255. $this->Shell->Schema = $this->getMock('CakeSchema');
  256. $this->Shell->Schema->expects($this->at(0))->method('read')->will($this->returnValue(array('schema data')));
  257. $this->Shell->Schema->expects($this->at(0))->method('write')->will($this->returnValue(true));
  258. $this->Shell->Schema->expects($this->at(1))->method('read');
  259. $this->Shell->Schema->expects($this->at(1))->method('write')->with(array('schema data', 'file' => 'schema_0.php'));
  260. $this->Shell->generate();
  261. }
  262. /**
  263. * test generate without a snapshot.
  264. *
  265. * @return void
  266. */
  267. public function testGenerateNoOverwrite() {
  268. touch(TMP . 'schema.php');
  269. $this->Shell->params['file'] = 'schema.php';
  270. $this->Shell->params['force'] = false;
  271. $this->Shell->args = array();
  272. $this->Shell->expects($this->once())->method('in')->will($this->returnValue('q'));
  273. $this->Shell->Schema = $this->getMock('CakeSchema');
  274. $this->Shell->Schema->path = TMP;
  275. $this->Shell->Schema->expects($this->never())->method('read');
  276. $this->Shell->generate();
  277. unlink(TMP . 'schema.php');
  278. }
  279. /**
  280. * test generate with overwriting of the schema files.
  281. *
  282. * @return void
  283. */
  284. public function testGenerateOverwrite() {
  285. touch(TMP . 'schema.php');
  286. $this->Shell->params['file'] = 'schema.php';
  287. $this->Shell->params['force'] = false;
  288. $this->Shell->args = array();
  289. $this->Shell->expects($this->once())->method('in')->will($this->returnValue('o'));
  290. $this->Shell->expects($this->at(2))->method('out')
  291. ->with(new PHPUnit_Framework_Constraint_PCREMatch('/Schema file:\s[a-z\.]+\sgenerated/'));
  292. $this->Shell->Schema = $this->getMock('CakeSchema');
  293. $this->Shell->Schema->path = TMP;
  294. $this->Shell->Schema->expects($this->once())->method('read')->will($this->returnValue(array('schema data')));
  295. $this->Shell->Schema->expects($this->once())->method('write')->will($this->returnValue(true));
  296. $this->Shell->Schema->expects($this->once())->method('read');
  297. $this->Shell->Schema->expects($this->once())->method('write')
  298. ->with(array('schema data', 'file' => 'schema.php'));
  299. $this->Shell->generate();
  300. unlink(TMP . 'schema.php');
  301. }
  302. /**
  303. * test that generate() can read plugin dirs and generate schema files for the models
  304. * in a plugin.
  305. *
  306. * @return void
  307. */
  308. public function testGenerateWithPlugins() {
  309. App::build(array(
  310. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  311. ), App::RESET);
  312. CakePlugin::load('TestPlugin');
  313. $this->db->cacheSources = false;
  314. $this->Shell->params = array(
  315. 'plugin' => 'TestPlugin',
  316. 'connection' => 'test',
  317. 'force' => false
  318. );
  319. $this->Shell->startup();
  320. $this->Shell->Schema->path = TMP . 'tests' . DS;
  321. $this->Shell->generate();
  322. $this->file = new File(TMP . 'tests' . DS . 'schema.php');
  323. $contents = $this->file->read();
  324. $this->assertRegExp('/class TestPluginSchema/', $contents);
  325. $this->assertRegExp('/public \$posts/', $contents);
  326. $this->assertRegExp('/public \$auth_users/', $contents);
  327. $this->assertRegExp('/public \$authors/', $contents);
  328. $this->assertRegExp('/public \$test_plugin_comments/', $contents);
  329. $this->assertNotRegExp('/public \$users/', $contents);
  330. $this->assertNotRegExp('/public \$articles/', $contents);
  331. CakePlugin::unload();
  332. }
  333. /**
  334. * test generate with specific models
  335. *
  336. * @return void
  337. */
  338. public function testGenerateModels() {
  339. App::build(array(
  340. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  341. ), App::RESET);
  342. CakePlugin::load('TestPlugin');
  343. $this->db->cacheSources = false;
  344. $this->Shell->params = array(
  345. 'plugin' => 'TestPlugin',
  346. 'connection' => 'test',
  347. 'models' => 'TestPluginComment',
  348. 'force' => false,
  349. 'overwrite' => true
  350. );
  351. $this->Shell->startup();
  352. $this->Shell->Schema->path = TMP . 'tests' . DS;
  353. $this->Shell->generate();
  354. $this->file = new File(TMP . 'tests' . DS . 'schema.php');
  355. $contents = $this->file->read();
  356. $this->assertRegExp('/class TestPluginSchema/', $contents);
  357. $this->assertRegExp('/public \$test_plugin_comments/', $contents);
  358. $this->assertNotRegExp('/public \$authors/', $contents);
  359. $this->assertNotRegExp('/public \$auth_users/', $contents);
  360. $this->assertNotRegExp('/public \$posts/', $contents);
  361. CakePlugin::unload();
  362. }
  363. /**
  364. * test generate with excluded tables
  365. *
  366. * @return void
  367. */
  368. public function testGenerateExclude() {
  369. Configure::write('Acl.database', 'test');
  370. $this->db->cacheSources = false;
  371. $this->Shell->params = array(
  372. 'connection' => 'test',
  373. 'force' => false,
  374. 'models' => 'Aro, Aco, Permission',
  375. 'overwrite' => true,
  376. 'exclude' => 'acos, aros',
  377. );
  378. $this->Shell->startup();
  379. $this->Shell->Schema->path = TMP . 'tests' . DS;
  380. $this->Shell->generate();
  381. $this->file = new File(TMP . 'tests' . DS . 'schema.php');
  382. $contents = $this->file->read();
  383. $this->assertNotContains('public $acos = array(', $contents);
  384. $this->assertNotContains('public $aros = array(', $contents);
  385. $this->assertContains('public $aros_acos = array(', $contents);
  386. }
  387. /**
  388. * Test schema run create with no table args.
  389. *
  390. * @return void
  391. */
  392. public function testCreateNoArgs() {
  393. $this->Shell->params = array(
  394. 'connection' => 'test'
  395. );
  396. $this->Shell->args = array('i18n');
  397. $this->Shell->startup();
  398. $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
  399. $this->Shell->create();
  400. $db = ConnectionManager::getDataSource('test');
  401. $db->cacheSources = false;
  402. $sources = $db->listSources();
  403. $this->assertTrue(in_array($db->config['prefix'] . 'i18n', $sources));
  404. $schema = new i18nSchema();
  405. $db->execute($db->dropSchema($schema));
  406. }
  407. /**
  408. * Test schema run create with no table args.
  409. *
  410. * @return void
  411. */
  412. public function testCreateWithTableArgs() {
  413. $db = ConnectionManager::getDataSource('test');
  414. $sources = $db->listSources();
  415. if (in_array('i18n', $sources)) {
  416. $this->markTestSkipped('i18n table already exists, cannot try to create it again.');
  417. }
  418. $this->Shell->params = array(
  419. 'connection' => 'test',
  420. 'name' => 'I18n',
  421. 'path' => APP . 'Config' . DS . 'Schema'
  422. );
  423. $this->Shell->args = array('I18n', 'i18n');
  424. $this->Shell->startup();
  425. $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
  426. $this->Shell->create();
  427. $db = ConnectionManager::getDataSource('test');
  428. $db->cacheSources = false;
  429. $sources = $db->listSources();
  430. $this->assertTrue(in_array($db->config['prefix'] . 'i18n', $sources), 'i18n should be present.');
  431. $schema = new I18nSchema();
  432. $db->execute($db->dropSchema($schema, 'i18n'));
  433. }
  434. /**
  435. * test run update with a table arg.
  436. *
  437. * @return void
  438. */
  439. public function testUpdateWithTable() {
  440. $this->Shell = $this->getMock(
  441. 'SchemaShell',
  442. array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_run'),
  443. array(&$this->Dispatcher)
  444. );
  445. $this->Shell->params = array(
  446. 'connection' => 'test',
  447. 'force' => true
  448. );
  449. $this->Shell->args = array('SchemaShellTest', 'articles');
  450. $this->Shell->startup();
  451. $this->Shell->expects($this->any())
  452. ->method('in')
  453. ->will($this->returnValue('y'));
  454. $this->Shell->expects($this->once())
  455. ->method('_run')
  456. ->with($this->arrayHasKey('articles'), 'update', $this->isInstanceOf('CakeSchema'));
  457. $this->Shell->update();
  458. }
  459. /**
  460. * test run update with a table arg. and checks that a CREATE statement is issued
  461. * table creation
  462. * @return void
  463. */
  464. public function testUpdateWithTableCreate() {
  465. $this->Shell = $this->getMock(
  466. 'SchemaShell',
  467. array('in', 'out', 'hr', 'createFile', 'error', 'err', '_stop', '_run'),
  468. array(&$this->Dispatcher)
  469. );
  470. $this->Shell->params = array(
  471. 'connection' => 'test',
  472. 'force' => true
  473. );
  474. $this->Shell->args = array('SchemaShellTest', 'newone');
  475. $this->Shell->startup();
  476. $this->Shell->expects($this->any())
  477. ->method('in')
  478. ->will($this->returnValue('y'));
  479. $r = $this->Shell->expects($this->once())
  480. ->method('_run')
  481. ->with($this->arrayHasKey('newone'), 'update', $this->isInstanceOf('CakeSchema'));
  482. $this->Shell->update();
  483. }
  484. /**
  485. * test that the plugin param creates the correct path in the schema object.
  486. *
  487. * @return void
  488. */
  489. public function testPluginParam() {
  490. App::build(array(
  491. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  492. ));
  493. CakePlugin::load('TestPlugin');
  494. $this->Shell->params = array(
  495. 'plugin' => 'TestPlugin',
  496. 'connection' => 'test'
  497. );
  498. $this->Shell->startup();
  499. $expected = CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS . 'TestPlugin' . DS . 'Config' . DS . 'Schema';
  500. $this->assertEquals($expected, $this->Shell->Schema->path);
  501. CakePlugin::unload();
  502. }
  503. /**
  504. * test that underscored names also result in CamelCased class names
  505. *
  506. * @return void
  507. */
  508. public function testName() {
  509. App::build(array(
  510. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  511. ));
  512. CakePlugin::load('TestPlugin');
  513. $this->Shell->params = array(
  514. 'plugin' => 'TestPlugin',
  515. 'connection' => 'test',
  516. 'name' => 'custom_name',
  517. 'force' => false,
  518. 'overwrite' => true,
  519. );
  520. $this->Shell->startup();
  521. if (file_exists($this->Shell->Schema->path . DS . 'custom_name.php')) {
  522. unlink($this->Shell->Schema->path . DS . 'custom_name.php');
  523. }
  524. $this->Shell->generate();
  525. $contents = file_get_contents($this->Shell->Schema->path . DS . 'custom_name.php');
  526. $this->assertRegExp('/class CustomNameSchema/', $contents);
  527. unlink($this->Shell->Schema->path . DS . 'custom_name.php');
  528. CakePlugin::unload();
  529. }
  530. /**
  531. * test that using Plugin.name with write.
  532. *
  533. * @return void
  534. */
  535. public function testPluginDotSyntaxWithCreate() {
  536. App::build(array(
  537. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  538. ));
  539. CakePlugin::load('TestPlugin');
  540. $this->Shell->params = array(
  541. 'connection' => 'test'
  542. );
  543. $this->Shell->args = array('TestPlugin.TestPluginApp');
  544. $this->Shell->startup();
  545. $this->Shell->expects($this->any())->method('in')->will($this->returnValue('y'));
  546. $this->Shell->create();
  547. $db = ConnectionManager::getDataSource('test');
  548. $sources = $db->listSources();
  549. $this->assertTrue(in_array($db->config['prefix'] . 'test_plugin_acos', $sources));
  550. $schema = new TestPluginAppSchema();
  551. $db->execute($db->dropSchema($schema, 'test_plugin_acos'));
  552. CakePlugin::unload();
  553. }
  554. }