CakeSchemaTest.php 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. <?php
  2. /**
  3. * Test for Schema database management
  4. *
  5. *
  6. * PHP 5
  7. *
  8. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  9. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. *
  11. * Licensed under The MIT License
  12. * For full copyright and license information, please see the LICENSE.txt
  13. * Redistributions of files must retain the above copyright notice
  14. *
  15. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  16. * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
  17. * @package Cake.Test.Case.Model
  18. * @since CakePHP(tm) v 1.2.0.5550
  19. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  20. */
  21. App::uses('CakeSchema', 'Model');
  22. App::uses('CakeTestFixture', 'TestSuite/Fixture');
  23. /**
  24. * Test for Schema database management
  25. *
  26. * @package Cake.Test.Case.Model
  27. */
  28. class MyAppSchema extends CakeSchema {
  29. /**
  30. * connection property
  31. *
  32. * @var string
  33. */
  34. public $connection = 'test';
  35. /**
  36. * comments property
  37. *
  38. * @var array
  39. */
  40. public $comments = array(
  41. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  42. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  43. 'user_id' => array('type' => 'integer', 'null' => false),
  44. 'title' => array('type' => 'string', 'null' => false, 'length' => 100),
  45. 'comment' => array('type' => 'text', 'null' => false, 'default' => null),
  46. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  47. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  48. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  49. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  50. );
  51. /**
  52. * posts property
  53. *
  54. * @var array
  55. */
  56. public $posts = array(
  57. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  58. 'author_id' => array('type' => 'integer', 'null' => true, 'default' => ''),
  59. 'title' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
  60. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  61. 'summary' => array('type' => 'text', 'null' => true),
  62. 'published' => array('type' => 'string', 'null' => true, 'default' => 'Y', 'length' => 1),
  63. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  64. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  65. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  66. );
  67. /**
  68. * _foo property
  69. *
  70. * @var array
  71. */
  72. protected $_foo = array('bar');
  73. /**
  74. * getVar method
  75. *
  76. * @param string $var Name of var
  77. * @return mixed
  78. */
  79. public function getVar($var) {
  80. if (!isset($this->$var)) {
  81. return null;
  82. }
  83. return $this->$var;
  84. }
  85. }
  86. /**
  87. * TestAppSchema class
  88. *
  89. * @package Cake.Test.Case.Model
  90. */
  91. class TestAppSchema extends CakeSchema {
  92. /**
  93. * name property
  94. *
  95. * @var string
  96. */
  97. public $name = 'MyApp';
  98. /**
  99. * comments property
  100. *
  101. * @var array
  102. */
  103. public $comments = array(
  104. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  105. 'article_id' => array('type' => 'integer', 'null' => false),
  106. 'user_id' => array('type' => 'integer', 'null' => false),
  107. 'comment' => array('type' => 'text', 'null' => true, 'default' => null),
  108. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  109. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  110. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  111. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  112. 'tableParameters' => array(),
  113. );
  114. /**
  115. * posts property
  116. *
  117. * @var array
  118. */
  119. public $posts = array(
  120. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  121. 'author_id' => array('type' => 'integer', 'null' => false),
  122. 'title' => array('type' => 'string', 'null' => false),
  123. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  124. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  125. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  126. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  127. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  128. 'tableParameters' => array(),
  129. );
  130. /**
  131. * posts_tags property
  132. *
  133. * @var array
  134. */
  135. public $posts_tags = array(
  136. 'post_id' => array('type' => 'integer', 'null' => false, 'key' => 'primary'),
  137. 'tag_id' => array('type' => 'string', 'null' => false, 'key' => 'primary'),
  138. 'indexes' => array('posts_tag' => array('column' => array('tag_id', 'post_id'), 'unique' => 1)),
  139. 'tableParameters' => array()
  140. );
  141. /**
  142. * tags property
  143. *
  144. * @var array
  145. */
  146. public $tags = array(
  147. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  148. 'tag' => array('type' => 'string', 'null' => false),
  149. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  150. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  151. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  152. 'tableParameters' => array()
  153. );
  154. /**
  155. * datatypes property
  156. *
  157. * @var array
  158. */
  159. public $datatypes = array(
  160. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  161. 'float_field' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => ''),
  162. 'huge_int' => array('type' => 'biginteger'),
  163. 'bool' => array('type' => 'boolean', 'null' => false, 'default' => false),
  164. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  165. 'tableParameters' => array()
  166. );
  167. /**
  168. * setup method
  169. *
  170. * @param mixed $version
  171. * @return void
  172. */
  173. public function setup($version) {
  174. }
  175. /**
  176. * teardown method
  177. *
  178. * @param mixed $version
  179. * @return void
  180. */
  181. public function teardown($version) {
  182. }
  183. }
  184. /**
  185. * SchemaPost class
  186. *
  187. * @package Cake.Test.Case.Model
  188. */
  189. class SchemaPost extends CakeTestModel {
  190. /**
  191. * useTable property
  192. *
  193. * @var string
  194. */
  195. public $useTable = 'posts';
  196. /**
  197. * hasMany property
  198. *
  199. * @var array
  200. */
  201. public $hasMany = array('SchemaComment');
  202. /**
  203. * hasAndBelongsToMany property
  204. *
  205. * @var array
  206. */
  207. public $hasAndBelongsToMany = array('SchemaTag');
  208. }
  209. /**
  210. * SchemaComment class
  211. *
  212. * @package Cake.Test.Case.Model
  213. */
  214. class SchemaComment extends CakeTestModel {
  215. /**
  216. * useTable property
  217. *
  218. * @var string
  219. */
  220. public $useTable = 'comments';
  221. /**
  222. * belongsTo property
  223. *
  224. * @var array
  225. */
  226. public $belongsTo = array('SchemaPost');
  227. }
  228. /**
  229. * SchemaTag class
  230. *
  231. * @package Cake.Test.Case.Model
  232. */
  233. class SchemaTag extends CakeTestModel {
  234. /**
  235. * useTable property
  236. *
  237. * @var string
  238. */
  239. public $useTable = 'tags';
  240. /**
  241. * hasAndBelongsToMany property
  242. *
  243. * @var array
  244. */
  245. public $hasAndBelongsToMany = array('SchemaPost');
  246. }
  247. /**
  248. * SchemaDatatype class
  249. *
  250. * @package Cake.Test.Case.Model
  251. */
  252. class SchemaDatatype extends CakeTestModel {
  253. /**
  254. * useTable property
  255. *
  256. * @var string
  257. */
  258. public $useTable = 'datatypes';
  259. }
  260. /**
  261. * Testdescribe class
  262. *
  263. * This class is defined purely to inherit the cacheSources variable otherwise
  264. * testSchemaCreateTable will fail if listSources has already been called and
  265. * its source cache populated - I.e. if the test is run within a group
  266. *
  267. * @uses CakeTestModel
  268. * @package Cake.Test.Case.Model
  269. */
  270. class Testdescribe extends CakeTestModel {
  271. }
  272. /**
  273. * SchemaCrossDatabase class
  274. *
  275. * @package Cake.Test.Case.Model
  276. */
  277. class SchemaCrossDatabase extends CakeTestModel {
  278. /**
  279. * useTable property
  280. *
  281. * @var string
  282. */
  283. public $useTable = 'cross_database';
  284. /**
  285. * useDbConfig property
  286. *
  287. * @var string
  288. */
  289. public $useDbConfig = 'test2';
  290. }
  291. /**
  292. * SchemaCrossDatabaseFixture class
  293. *
  294. * @package Cake.Test.Case.Model
  295. */
  296. class SchemaCrossDatabaseFixture extends CakeTestFixture {
  297. /**
  298. * name property
  299. *
  300. * @var string
  301. */
  302. public $name = 'CrossDatabase';
  303. /**
  304. * table property
  305. *
  306. * @var string
  307. */
  308. public $table = 'cross_database';
  309. /**
  310. * fields property
  311. *
  312. * @var array
  313. */
  314. public $fields = array(
  315. 'id' => array('type' => 'integer', 'key' => 'primary'),
  316. 'name' => 'string'
  317. );
  318. /**
  319. * records property
  320. *
  321. * @var array
  322. */
  323. public $records = array(
  324. array('id' => 1, 'name' => 'First'),
  325. array('id' => 2, 'name' => 'Second'),
  326. );
  327. }
  328. /**
  329. * SchemaPrefixAuthUser class
  330. *
  331. * @package Cake.Test.Case.Model
  332. */
  333. class SchemaPrefixAuthUser extends CakeTestModel {
  334. /**
  335. * table prefix
  336. *
  337. * @var string
  338. */
  339. public $tablePrefix = 'auth_';
  340. /**
  341. * useTable
  342. *
  343. * @var string
  344. */
  345. public $useTable = 'users';
  346. }
  347. /**
  348. * CakeSchemaTest
  349. *
  350. * @package Cake.Test.Case.Model
  351. */
  352. class CakeSchemaTest extends CakeTestCase {
  353. /**
  354. * fixtures property
  355. *
  356. * @var array
  357. */
  358. public $fixtures = array(
  359. 'core.post', 'core.tag', 'core.posts_tag', 'core.test_plugin_comment',
  360. 'core.datatype', 'core.auth_user', 'core.author',
  361. 'core.test_plugin_article', 'core.user', 'core.comment',
  362. 'core.prefix_test'
  363. );
  364. /**
  365. * setUp method
  366. *
  367. * @return void
  368. */
  369. public function setUp() {
  370. parent::setUp();
  371. ConnectionManager::getDataSource('test')->cacheSources = false;
  372. $this->Schema = new TestAppSchema();
  373. }
  374. /**
  375. * tearDown method
  376. *
  377. * @return void
  378. */
  379. public function tearDown() {
  380. parent::tearDown();
  381. if (file_exists(TMP . 'tests' . DS . 'schema.php')) {
  382. unlink(TMP . 'tests' . DS . 'schema.php');
  383. }
  384. unset($this->Schema);
  385. CakePlugin::unload();
  386. }
  387. /**
  388. * testSchemaName method
  389. *
  390. * @return void
  391. */
  392. public function testSchemaName() {
  393. $Schema = new CakeSchema();
  394. $this->assertEquals(Inflector::camelize(Inflector::slug(APP_DIR)), $Schema->name);
  395. Configure::write('App.dir', 'Some.name.with.dots');
  396. $Schema = new CakeSchema();
  397. $this->assertEquals('SomeNameWithDots', $Schema->name);
  398. Configure::write('App.dir', 'Some-name-with-dashes');
  399. $Schema = new CakeSchema();
  400. $this->assertEquals('SomeNameWithDashes', $Schema->name);
  401. Configure::write('App.dir', 'Some name with spaces');
  402. $Schema = new CakeSchema();
  403. $this->assertEquals('SomeNameWithSpaces', $Schema->name);
  404. Configure::write('App.dir', 'Some,name;with&weird=characters');
  405. $Schema = new CakeSchema();
  406. $this->assertEquals('SomeNameWithWeirdCharacters', $Schema->name);
  407. Configure::write('App.dir', 'app');
  408. }
  409. /**
  410. * testSchemaRead method
  411. *
  412. * @return void
  413. */
  414. public function testSchemaRead() {
  415. $read = $this->Schema->read(array(
  416. 'connection' => 'test',
  417. 'name' => 'TestApp',
  418. 'models' => array('SchemaPost', 'SchemaComment', 'SchemaTag', 'SchemaDatatype')
  419. ));
  420. unset($read['tables']['missing']);
  421. $expected = array('comments', 'datatypes', 'posts', 'posts_tags', 'tags');
  422. foreach ($expected as $table) {
  423. $this->assertTrue(isset($read['tables'][$table]), 'Missing table ' . $table);
  424. }
  425. foreach ($this->Schema->tables as $table => $fields) {
  426. $this->assertEquals(array_keys($fields), array_keys($read['tables'][$table]));
  427. }
  428. if (isset($read['tables']['datatypes']['float_field']['length'])) {
  429. $this->assertEquals(
  430. $read['tables']['datatypes']['float_field']['length'],
  431. $this->Schema->tables['datatypes']['float_field']['length']
  432. );
  433. }
  434. $this->assertEquals(
  435. $read['tables']['datatypes']['float_field']['type'],
  436. $this->Schema->tables['datatypes']['float_field']['type']
  437. );
  438. $this->assertEquals(
  439. $read['tables']['datatypes']['float_field']['null'],
  440. $this->Schema->tables['datatypes']['float_field']['null']
  441. );
  442. $db = ConnectionManager::getDataSource('test');
  443. $config = $db->config;
  444. $config['prefix'] = 'schema_test_prefix_';
  445. ConnectionManager::create('schema_prefix', $config);
  446. $read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false));
  447. $this->assertTrue(empty($read['tables']));
  448. $read = $this->Schema->read(array(
  449. 'connection' => 'test',
  450. 'name' => 'TestApp',
  451. 'models' => array('SchemaComment', 'SchemaTag', 'SchemaPost')
  452. ));
  453. $this->assertFalse(isset($read['tables']['missing']['posts_tags']), 'Join table marked as missing');
  454. }
  455. /**
  456. * testSchemaReadWithAppModel method
  457. *
  458. * @return void
  459. */
  460. public function testSchemaReadWithAppModel() {
  461. $connections = ConnectionManager::enumConnectionObjects();
  462. ConnectionManager::drop('default');
  463. ConnectionManager::create('default', $connections['test']);
  464. try {
  465. $this->Schema->read(array(
  466. 'connection' => 'default',
  467. 'name' => 'TestApp',
  468. 'models' => array('AppModel')
  469. ));
  470. } catch(MissingTableException $mte) {
  471. ConnectionManager::drop('default');
  472. $this->fail($mte->getMessage());
  473. }
  474. ConnectionManager::drop('default');
  475. }
  476. /**
  477. * testSchemaReadWithOddTablePrefix method
  478. *
  479. * @return void
  480. */
  481. public function testSchemaReadWithOddTablePrefix() {
  482. $config = ConnectionManager::getDataSource('test')->config;
  483. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  484. $SchemaPost = ClassRegistry::init('SchemaPost');
  485. $SchemaPost->tablePrefix = 'po';
  486. $SchemaPost->useTable = 'sts';
  487. $read = $this->Schema->read(array(
  488. 'connection' => 'test',
  489. 'name' => 'TestApp',
  490. 'models' => array('SchemaPost')
  491. ));
  492. $this->assertFalse(isset($read['tables']['missing']['posts']), 'Posts table was not read from tablePrefix');
  493. }
  494. /**
  495. * test read() with tablePrefix properties.
  496. *
  497. * @return void
  498. */
  499. public function testSchemaReadWithTablePrefix() {
  500. $config = ConnectionManager::getDataSource('test')->config;
  501. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  502. $Schema = new CakeSchema();
  503. $read = $Schema->read(array(
  504. 'connection' => 'test',
  505. 'name' => 'TestApp',
  506. 'models' => array('SchemaPrefixAuthUser')
  507. ));
  508. unset($read['tables']['missing']);
  509. $this->assertTrue(isset($read['tables']['auth_users']), 'auth_users key missing %s');
  510. }
  511. /**
  512. * test reading schema with config prefix.
  513. *
  514. * @return void
  515. */
  516. public function testSchemaReadWithConfigPrefix() {
  517. $this->skipIf($this->db instanceof Sqlite, 'Cannot open 2 connections to Sqlite');
  518. $db = ConnectionManager::getDataSource('test');
  519. $config = $db->config;
  520. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  521. $config['prefix'] = 'schema_test_prefix_';
  522. ConnectionManager::create('schema_prefix', $config);
  523. $read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false));
  524. $this->assertTrue(empty($read['tables']));
  525. $config['prefix'] = 'prefix_';
  526. ConnectionManager::create('schema_prefix2', $config);
  527. $read = $this->Schema->read(array(
  528. 'connection' => 'schema_prefix2',
  529. 'name' => 'TestApp',
  530. 'models' => false));
  531. $this->assertTrue(isset($read['tables']['prefix_tests']));
  532. }
  533. /**
  534. * test reading schema from plugins.
  535. *
  536. * @return void
  537. */
  538. public function testSchemaReadWithPlugins() {
  539. App::objects('model', null, false);
  540. App::build(array(
  541. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  542. ));
  543. CakePlugin::load('TestPlugin');
  544. $Schema = new CakeSchema();
  545. $Schema->plugin = 'TestPlugin';
  546. $read = $Schema->read(array(
  547. 'connection' => 'test',
  548. 'name' => 'TestApp',
  549. 'models' => true
  550. ));
  551. unset($read['tables']['missing']);
  552. $this->assertTrue(isset($read['tables']['auth_users']));
  553. $this->assertTrue(isset($read['tables']['authors']));
  554. $this->assertTrue(isset($read['tables']['test_plugin_comments']));
  555. $this->assertTrue(isset($read['tables']['posts']));
  556. $this->assertTrue(count($read['tables']) >= 4);
  557. App::build();
  558. }
  559. /**
  560. * test reading schema with tables from another database.
  561. *
  562. * @return void
  563. */
  564. public function testSchemaReadWithCrossDatabase() {
  565. $config = ConnectionManager::enumConnectionObjects();
  566. $this->skipIf(
  567. !isset($config['test']) || !isset($config['test2']),
  568. 'Primary and secondary test databases not configured, ' .
  569. 'skipping cross-database join tests. ' .
  570. 'To run these tests, you must define $test and $test2 in your database configuration.'
  571. );
  572. $db = ConnectionManager::getDataSource('test2');
  573. $fixture = new SchemaCrossDatabaseFixture();
  574. $fixture->create($db);
  575. $fixture->insert($db);
  576. $read = $this->Schema->read(array(
  577. 'connection' => 'test',
  578. 'name' => 'TestApp',
  579. 'models' => array('SchemaCrossDatabase', 'SchemaPost')
  580. ));
  581. $this->assertTrue(isset($read['tables']['posts']));
  582. $this->assertFalse(isset($read['tables']['cross_database']), 'Cross database should not appear');
  583. $this->assertFalse(isset($read['tables']['missing']['cross_database']), 'Cross database should not appear');
  584. $read = $this->Schema->read(array(
  585. 'connection' => 'test2',
  586. 'name' => 'TestApp',
  587. 'models' => array('SchemaCrossDatabase', 'SchemaPost')
  588. ));
  589. $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear');
  590. $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear');
  591. $this->assertTrue(isset($read['tables']['cross_database']));
  592. $fixture->drop($db);
  593. }
  594. /**
  595. * test that tables are generated correctly
  596. *
  597. * @return void
  598. */
  599. public function testGenerateTable() {
  600. $posts = array(
  601. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  602. 'author_id' => array('type' => 'integer', 'null' => false),
  603. 'title' => array('type' => 'string', 'null' => false),
  604. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  605. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  606. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  607. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  608. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  609. );
  610. $result = $this->Schema->generateTable('posts', $posts);
  611. $this->assertRegExp('/public \$posts/', $result);
  612. $posts = array(
  613. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  614. 'author_id' => array('type' => 'integer', 'null' => false),
  615. 'title' => array('type' => 'string', 'null' => false),
  616. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  617. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  618. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  619. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  620. 'indexes' => array(
  621. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  622. 'MyFtIndex' => array('column' => array('title', 'body'), 'type' => 'fulltext')
  623. )
  624. );
  625. $result = $this->Schema->generateTable('fields', $posts);
  626. $this->assertRegExp('/public \$fields/', $result);
  627. $this->assertRegExp('/\'type\' \=\> \'fulltext\'/', $result);
  628. }
  629. /**
  630. * testSchemaWrite method
  631. *
  632. * @return void
  633. */
  634. public function testSchemaWrite() {
  635. $write = $this->Schema->write(array(
  636. 'name' => 'MyOtherApp',
  637. 'tables' => $this->Schema->tables,
  638. 'path' => TMP . 'tests'
  639. ));
  640. $file = file_get_contents(TMP . 'tests' . DS . 'schema.php');
  641. $this->assertEquals($write, $file);
  642. require_once TMP . 'tests' . DS . 'schema.php';
  643. $OtherSchema = new MyOtherAppSchema();
  644. $this->assertEquals($this->Schema->tables, $OtherSchema->tables);
  645. }
  646. /**
  647. * testSchemaComparison method
  648. *
  649. * @return void
  650. */
  651. public function testSchemaComparison() {
  652. $New = new MyAppSchema();
  653. $compare = $New->compare($this->Schema);
  654. $expected = array(
  655. 'comments' => array(
  656. 'add' => array(
  657. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'after' => 'id'),
  658. 'title' => array('type' => 'string', 'null' => false, 'length' => 100, 'after' => 'user_id'),
  659. ),
  660. 'drop' => array(
  661. 'article_id' => array('type' => 'integer', 'null' => false),
  662. 'tableParameters' => array(),
  663. ),
  664. 'change' => array(
  665. 'comment' => array('type' => 'text', 'null' => false, 'default' => null),
  666. )
  667. ),
  668. 'posts' => array(
  669. 'add' => array(
  670. 'summary' => array('type' => 'text', 'null' => true, 'after' => 'body'),
  671. ),
  672. 'drop' => array(
  673. 'tableParameters' => array(),
  674. ),
  675. 'change' => array(
  676. 'author_id' => array('type' => 'integer', 'null' => true, 'default' => ''),
  677. 'title' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
  678. 'published' => array('type' => 'string', 'null' => true, 'default' => 'Y', 'length' => 1)
  679. )
  680. ),
  681. );
  682. $this->assertEquals($expected, $compare);
  683. $this->assertNull($New->getVar('comments'));
  684. $this->assertEquals(array('bar'), $New->getVar('_foo'));
  685. $tables = array(
  686. 'missing' => array(
  687. 'categories' => array(
  688. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  689. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  690. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  691. 'name' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 100),
  692. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  693. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  694. )
  695. ),
  696. 'ratings' => array(
  697. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  698. 'foreign_key' => array('type' => 'integer', 'null' => false, 'default' => null),
  699. 'model' => array('type' => 'varchar', 'null' => false, 'default' => null),
  700. 'value' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => null),
  701. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  702. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  703. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  704. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  705. )
  706. );
  707. $compare = $New->compare($this->Schema, $tables);
  708. $expected = array(
  709. 'ratings' => array(
  710. 'create' => array(
  711. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  712. 'foreign_key' => array('type' => 'integer', 'null' => false, 'default' => null),
  713. 'model' => array('type' => 'varchar', 'null' => false, 'default' => null),
  714. 'value' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => null),
  715. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  716. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  717. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  718. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  719. )
  720. )
  721. );
  722. $this->assertEquals($expected, $compare);
  723. }
  724. /**
  725. * test comparing '' and null and making sure they are different.
  726. *
  727. * @return void
  728. */
  729. public function testCompareEmptyStringAndNull() {
  730. $One = new CakeSchema(array(
  731. 'posts' => array(
  732. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  733. 'name' => array('type' => 'string', 'null' => false, 'default' => '')
  734. )
  735. ));
  736. $Two = new CakeSchema(array(
  737. 'posts' => array(
  738. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  739. 'name' => array('type' => 'string', 'null' => false, 'default' => null)
  740. )
  741. ));
  742. $compare = $One->compare($Two);
  743. $expected = array(
  744. 'posts' => array(
  745. 'change' => array(
  746. 'name' => array('type' => 'string', 'null' => false, 'default' => null)
  747. )
  748. )
  749. );
  750. $this->assertEquals($expected, $compare);
  751. }
  752. /**
  753. * Test comparing tableParameters and indexes.
  754. *
  755. * @return void
  756. */
  757. public function testTableParametersAndIndexComparison() {
  758. $old = array(
  759. 'posts' => array(
  760. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  761. 'author_id' => array('type' => 'integer', 'null' => false),
  762. 'title' => array('type' => 'string', 'null' => false),
  763. 'indexes' => array(
  764. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  765. ),
  766. 'tableParameters' => array(
  767. 'charset' => 'latin1',
  768. 'collate' => 'latin1_general_ci'
  769. )
  770. ),
  771. 'comments' => array(
  772. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  773. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  774. 'comment' => array('type' => 'text'),
  775. 'indexes' => array(
  776. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  777. 'post_id' => array('column' => 'post_id'),
  778. ),
  779. 'tableParameters' => array(
  780. 'engine' => 'InnoDB',
  781. 'charset' => 'latin1',
  782. 'collate' => 'latin1_general_ci'
  783. )
  784. )
  785. );
  786. $new = array(
  787. 'posts' => array(
  788. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  789. 'author_id' => array('type' => 'integer', 'null' => false),
  790. 'title' => array('type' => 'string', 'null' => false),
  791. 'indexes' => array(
  792. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  793. 'author_id' => array('column' => 'author_id'),
  794. ),
  795. 'tableParameters' => array(
  796. 'charset' => 'utf8',
  797. 'collate' => 'utf8_general_ci',
  798. 'engine' => 'MyISAM'
  799. )
  800. ),
  801. 'comments' => array(
  802. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  803. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  804. 'comment' => array('type' => 'text'),
  805. 'indexes' => array(
  806. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  807. ),
  808. 'tableParameters' => array(
  809. 'charset' => 'utf8',
  810. 'collate' => 'utf8_general_ci'
  811. )
  812. )
  813. );
  814. $compare = $this->Schema->compare($old, $new);
  815. $expected = array(
  816. 'posts' => array(
  817. 'add' => array(
  818. 'indexes' => array('author_id' => array('column' => 'author_id')),
  819. ),
  820. 'change' => array(
  821. 'tableParameters' => array(
  822. 'charset' => 'utf8',
  823. 'collate' => 'utf8_general_ci',
  824. 'engine' => 'MyISAM'
  825. )
  826. )
  827. ),
  828. 'comments' => array(
  829. 'drop' => array(
  830. 'indexes' => array('post_id' => array('column' => 'post_id')),
  831. ),
  832. 'change' => array(
  833. 'tableParameters' => array(
  834. 'charset' => 'utf8',
  835. 'collate' => 'utf8_general_ci',
  836. )
  837. )
  838. )
  839. );
  840. $this->assertEquals($expected, $compare);
  841. }
  842. /**
  843. * Test comparing with field changed from VARCHAR to DATETIME
  844. *
  845. * @return void
  846. */
  847. public function testCompareVarcharToDatetime() {
  848. $old = array(
  849. 'posts' => array(
  850. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  851. 'author_id' => array('type' => 'integer', 'null' => false),
  852. 'title' => array('type' => 'string', 'null' => true, 'length' => 45),
  853. 'indexes' => array(
  854. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  855. ),
  856. 'tableParameters' => array(
  857. 'charset' => 'latin1',
  858. 'collate' => 'latin1_general_ci'
  859. )
  860. ),
  861. );
  862. $new = array(
  863. 'posts' => array(
  864. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  865. 'author_id' => array('type' => 'integer', 'null' => false),
  866. 'title' => array('type' => 'datetime', 'null' => false),
  867. 'indexes' => array(
  868. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  869. ),
  870. 'tableParameters' => array(
  871. 'charset' => 'latin1',
  872. 'collate' => 'latin1_general_ci'
  873. )
  874. ),
  875. );
  876. $compare = $this->Schema->compare($old, $new);
  877. $expected = array(
  878. 'posts' => array(
  879. 'change' => array(
  880. 'title' => array(
  881. 'type' => 'datetime',
  882. 'null' => false,
  883. )
  884. )
  885. ),
  886. );
  887. $this->assertEquals($expected, $compare, 'Invalid SQL, datetime does not have length');
  888. }
  889. /**
  890. * testSchemaLoading method
  891. *
  892. * @return void
  893. */
  894. public function testSchemaLoading() {
  895. $Other = $this->Schema->load(array('name' => 'MyOtherApp', 'path' => TMP . 'tests'));
  896. $this->assertEquals('MyOtherApp', $Other->name);
  897. $this->assertEquals($Other->tables, $this->Schema->tables);
  898. }
  899. /**
  900. * test loading schema files inside of plugins.
  901. *
  902. * @return void
  903. */
  904. public function testSchemaLoadingFromPlugin() {
  905. App::build(array(
  906. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  907. ));
  908. CakePlugin::load('TestPlugin');
  909. $Other = $this->Schema->load(array('name' => 'TestPluginApp', 'plugin' => 'TestPlugin'));
  910. $this->assertEquals('TestPluginApp', $Other->name);
  911. $this->assertEquals(array('test_plugin_acos'), array_keys($Other->tables));
  912. App::build();
  913. }
  914. /**
  915. * testSchemaCreateTable method
  916. *
  917. * @return void
  918. */
  919. public function testSchemaCreateTable() {
  920. $db = ConnectionManager::getDataSource('test');
  921. $db->cacheSources = false;
  922. $Schema = new CakeSchema(array(
  923. 'connection' => 'test',
  924. 'testdescribes' => array(
  925. 'id' => array('type' => 'integer', 'key' => 'primary'),
  926. 'int_null' => array('type' => 'integer', 'null' => true),
  927. 'int_not_null' => array('type' => 'integer', 'null' => false),
  928. ),
  929. ));
  930. $sql = $db->createSchema($Schema);
  931. $col = $Schema->tables['testdescribes']['int_null'];
  932. $col['name'] = 'int_null';
  933. $column = $this->db->buildColumn($col);
  934. $this->assertRegExp('/' . preg_quote($column, '/') . '/', $sql);
  935. $col = $Schema->tables['testdescribes']['int_not_null'];
  936. $col['name'] = 'int_not_null';
  937. $column = $this->db->buildColumn($col);
  938. $this->assertRegExp('/' . preg_quote($column, '/') . '/', $sql);
  939. }
  940. }