CakeSchemaTest.php 28 KB

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