CakeSchemaTest.php 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031
  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(Inflector::camelize(Inflector::slug(APP_DIR)), $Schema->name);
  393. Configure::write('App.dir', 'Some.name.with.dots');
  394. $Schema = new CakeSchema();
  395. $this->assertEquals('SomeNameWithDots', $Schema->name);
  396. Configure::write('App.dir', 'Some-name-with-dashes');
  397. $Schema = new CakeSchema();
  398. $this->assertEquals('SomeNameWithDashes', $Schema->name);
  399. Configure::write('App.dir', 'Some name with spaces');
  400. $Schema = new CakeSchema();
  401. $this->assertEquals('SomeNameWithSpaces', $Schema->name);
  402. Configure::write('App.dir', 'Some,name;with&weird=characters');
  403. $Schema = new CakeSchema();
  404. $this->assertEquals('SomeNameWithWeirdCharacters', $Schema->name);
  405. Configure::write('App.dir', 'app');
  406. }
  407. /**
  408. * testSchemaRead method
  409. *
  410. * @return void
  411. */
  412. public function testSchemaRead() {
  413. $read = $this->Schema->read(array(
  414. 'connection' => 'test',
  415. 'name' => 'TestApp',
  416. 'models' => array('SchemaPost', 'SchemaComment', 'SchemaTag', 'SchemaDatatype')
  417. ));
  418. unset($read['tables']['missing']);
  419. $expected = array('comments', 'datatypes', 'posts', 'posts_tags', 'tags');
  420. foreach ($expected as $table) {
  421. $this->assertTrue(isset($read['tables'][$table]), 'Missing table ' . $table);
  422. }
  423. foreach ($this->Schema->tables as $table => $fields) {
  424. $this->assertEquals(array_keys($fields), array_keys($read['tables'][$table]));
  425. }
  426. if (isset($read['tables']['datatypes']['float_field']['length'])) {
  427. $this->assertEquals(
  428. $read['tables']['datatypes']['float_field']['length'],
  429. $this->Schema->tables['datatypes']['float_field']['length']
  430. );
  431. }
  432. $this->assertEquals(
  433. $read['tables']['datatypes']['float_field']['type'],
  434. $this->Schema->tables['datatypes']['float_field']['type']
  435. );
  436. $this->assertEquals(
  437. $read['tables']['datatypes']['float_field']['null'],
  438. $this->Schema->tables['datatypes']['float_field']['null']
  439. );
  440. $db = ConnectionManager::getDataSource('test');
  441. $config = $db->config;
  442. $config['prefix'] = 'schema_test_prefix_';
  443. ConnectionManager::create('schema_prefix', $config);
  444. $read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false));
  445. $this->assertTrue(empty($read['tables']));
  446. $read = $this->Schema->read(array(
  447. 'connection' => 'test',
  448. 'name' => 'TestApp',
  449. 'models' => array('SchemaComment', 'SchemaTag', 'SchemaPost')
  450. ));
  451. $this->assertFalse(isset($read['tables']['missing']['posts_tags']), 'Join table marked as missing');
  452. }
  453. /**
  454. * testSchemaReadWithAppModel method
  455. *
  456. * @return void
  457. */
  458. public function testSchemaReadWithAppModel() {
  459. $connections = ConnectionManager::enumConnectionObjects();
  460. ConnectionManager::drop('default');
  461. ConnectionManager::create('default', $connections['test']);
  462. try {
  463. $this->Schema->read(array(
  464. 'connection' => 'default',
  465. 'name' => 'TestApp',
  466. 'models' => array('AppModel')
  467. ));
  468. } catch(MissingTableException $mte) {
  469. ConnectionManager::drop('default');
  470. $this->fail($mte->getMessage());
  471. }
  472. ConnectionManager::drop('default');
  473. }
  474. /**
  475. * testSchemaReadWithOddTablePrefix method
  476. *
  477. * @return void
  478. */
  479. public function testSchemaReadWithOddTablePrefix() {
  480. $config = ConnectionManager::getDataSource('test')->config;
  481. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  482. $SchemaPost = ClassRegistry::init('SchemaPost');
  483. $SchemaPost->tablePrefix = 'po';
  484. $SchemaPost->useTable = 'sts';
  485. $read = $this->Schema->read(array(
  486. 'connection' => 'test',
  487. 'name' => 'TestApp',
  488. 'models' => array('SchemaPost')
  489. ));
  490. $this->assertFalse(isset($read['tables']['missing']['posts']), 'Posts table was not read from tablePrefix');
  491. }
  492. /**
  493. * test read() with tablePrefix properties.
  494. *
  495. * @return void
  496. */
  497. public function testSchemaReadWithTablePrefix() {
  498. $config = ConnectionManager::getDataSource('test')->config;
  499. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  500. $Schema = new CakeSchema();
  501. $read = $Schema->read(array(
  502. 'connection' => 'test',
  503. 'name' => 'TestApp',
  504. 'models' => array('SchemaPrefixAuthUser')
  505. ));
  506. unset($read['tables']['missing']);
  507. $this->assertTrue(isset($read['tables']['auth_users']), 'auth_users key missing %s');
  508. }
  509. /**
  510. * test reading schema with config prefix.
  511. *
  512. * @return void
  513. */
  514. public function testSchemaReadWithConfigPrefix() {
  515. $this->skipIf($this->db instanceof Sqlite, 'Cannot open 2 connections to Sqlite');
  516. $db = ConnectionManager::getDataSource('test');
  517. $config = $db->config;
  518. $this->skipIf(!empty($config['prefix']), 'This test can not be executed with datasource prefix set.');
  519. $config['prefix'] = 'schema_test_prefix_';
  520. ConnectionManager::create('schema_prefix', $config);
  521. $read = $this->Schema->read(array('connection' => 'schema_prefix', 'models' => false));
  522. $this->assertTrue(empty($read['tables']));
  523. $config['prefix'] = 'prefix_';
  524. ConnectionManager::create('schema_prefix2', $config);
  525. $read = $this->Schema->read(array(
  526. 'connection' => 'schema_prefix2',
  527. 'name' => 'TestApp',
  528. 'models' => false));
  529. $this->assertTrue(isset($read['tables']['prefix_tests']));
  530. }
  531. /**
  532. * test reading schema from plugins.
  533. *
  534. * @return void
  535. */
  536. public function testSchemaReadWithPlugins() {
  537. App::objects('model', null, false);
  538. App::build(array(
  539. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  540. ));
  541. CakePlugin::load('TestPlugin');
  542. $Schema = new CakeSchema();
  543. $Schema->plugin = 'TestPlugin';
  544. $read = $Schema->read(array(
  545. 'connection' => 'test',
  546. 'name' => 'TestApp',
  547. 'models' => true
  548. ));
  549. unset($read['tables']['missing']);
  550. $this->assertTrue(isset($read['tables']['auth_users']));
  551. $this->assertTrue(isset($read['tables']['authors']));
  552. $this->assertTrue(isset($read['tables']['test_plugin_comments']));
  553. $this->assertTrue(isset($read['tables']['posts']));
  554. $this->assertTrue(count($read['tables']) >= 4);
  555. App::build();
  556. }
  557. /**
  558. * test reading schema with tables from another database.
  559. *
  560. * @return void
  561. */
  562. public function testSchemaReadWithCrossDatabase() {
  563. $config = ConnectionManager::enumConnectionObjects();
  564. $this->skipIf(
  565. !isset($config['test']) || !isset($config['test2']),
  566. 'Primary and secondary test databases not configured, ' .
  567. 'skipping cross-database join tests. ' .
  568. 'To run these tests, you must define $test and $test2 in your database configuration.'
  569. );
  570. $db = ConnectionManager::getDataSource('test2');
  571. $fixture = new SchemaCrossDatabaseFixture();
  572. $fixture->create($db);
  573. $fixture->insert($db);
  574. $read = $this->Schema->read(array(
  575. 'connection' => 'test',
  576. 'name' => 'TestApp',
  577. 'models' => array('SchemaCrossDatabase', 'SchemaPost')
  578. ));
  579. $this->assertTrue(isset($read['tables']['posts']));
  580. $this->assertFalse(isset($read['tables']['cross_database']), 'Cross database should not appear');
  581. $this->assertFalse(isset($read['tables']['missing']['cross_database']), 'Cross database should not appear');
  582. $read = $this->Schema->read(array(
  583. 'connection' => 'test2',
  584. 'name' => 'TestApp',
  585. 'models' => array('SchemaCrossDatabase', 'SchemaPost')
  586. ));
  587. $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear');
  588. $this->assertFalse(isset($read['tables']['posts']), 'Posts should not appear');
  589. $this->assertTrue(isset($read['tables']['cross_database']));
  590. $fixture->drop($db);
  591. }
  592. /**
  593. * test that tables are generated correctly
  594. *
  595. * @return void
  596. */
  597. public function testGenerateTable() {
  598. $posts = array(
  599. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  600. 'author_id' => array('type' => 'integer', 'null' => false),
  601. 'title' => array('type' => 'string', 'null' => false),
  602. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  603. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  604. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  605. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  606. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)),
  607. );
  608. $result = $this->Schema->generateTable('posts', $posts);
  609. $this->assertRegExp('/public \$posts/', $result);
  610. $posts = array(
  611. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  612. 'author_id' => array('type' => 'integer', 'null' => false),
  613. 'title' => array('type' => 'string', 'null' => false),
  614. 'body' => array('type' => 'text', 'null' => true, 'default' => null),
  615. 'published' => array('type' => 'string', 'null' => true, 'default' => 'N', 'length' => 1),
  616. 'created' => array('type' => 'datetime', 'null' => true, 'default' => null),
  617. 'updated' => array('type' => 'datetime', 'null' => true, 'default' => null),
  618. 'indexes' => array(
  619. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  620. 'MyFtIndex' => array('column' => array('title', 'body'), 'type' => 'fulltext')
  621. )
  622. );
  623. $result = $this->Schema->generateTable('fields', $posts);
  624. $this->assertRegExp('/public \$fields/', $result);
  625. $this->assertRegExp('/\'type\' \=\> \'fulltext\'/', $result);
  626. }
  627. /**
  628. * testSchemaWrite method
  629. *
  630. * @return void
  631. */
  632. public function testSchemaWrite() {
  633. $write = $this->Schema->write(array(
  634. 'name' => 'MyOtherApp',
  635. 'tables' => $this->Schema->tables,
  636. 'path' => TMP . 'tests'
  637. ));
  638. $file = file_get_contents(TMP . 'tests' . DS . 'schema.php');
  639. $this->assertEquals($write, $file);
  640. require_once TMP . 'tests' . DS . 'schema.php';
  641. $OtherSchema = new MyOtherAppSchema();
  642. $this->assertEquals($this->Schema->tables, $OtherSchema->tables);
  643. }
  644. /**
  645. * testSchemaComparison method
  646. *
  647. * @return void
  648. */
  649. public function testSchemaComparison() {
  650. $New = new MyAppSchema();
  651. $compare = $New->compare($this->Schema);
  652. $expected = array(
  653. 'comments' => array(
  654. 'add' => array(
  655. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'after' => 'id'),
  656. 'title' => array('type' => 'string', 'null' => false, 'length' => 100, 'after' => 'user_id'),
  657. ),
  658. 'drop' => array(
  659. 'article_id' => array('type' => 'integer', 'null' => false),
  660. 'tableParameters' => array(),
  661. ),
  662. 'change' => array(
  663. 'comment' => array('type' => 'text', 'null' => false, 'default' => null),
  664. )
  665. ),
  666. 'posts' => array(
  667. 'add' => array(
  668. 'summary' => array('type' => 'text', 'null' => true, 'after' => 'body'),
  669. ),
  670. 'drop' => array(
  671. 'tableParameters' => array(),
  672. ),
  673. 'change' => array(
  674. 'author_id' => array('type' => 'integer', 'null' => true, 'default' => ''),
  675. 'title' => array('type' => 'string', 'null' => false, 'default' => 'Title'),
  676. 'published' => array('type' => 'string', 'null' => true, 'default' => 'Y', 'length' => 1)
  677. )
  678. ),
  679. );
  680. $this->assertEquals($expected, $compare);
  681. $this->assertNull($New->getVar('comments'));
  682. $this->assertEquals(array('bar'), $New->getVar('_foo'));
  683. $tables = array(
  684. 'missing' => array(
  685. 'categories' => array(
  686. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  687. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  688. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  689. 'name' => array('type' => 'string', 'null' => false, 'default' => null, 'length' => 100),
  690. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  691. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  692. )
  693. ),
  694. 'ratings' => array(
  695. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  696. 'foreign_key' => array('type' => 'integer', 'null' => false, 'default' => null),
  697. 'model' => array('type' => 'varchar', 'null' => false, 'default' => null),
  698. 'value' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => null),
  699. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  700. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  701. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  702. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  703. )
  704. );
  705. $compare = $New->compare($this->Schema, $tables);
  706. $expected = array(
  707. 'ratings' => array(
  708. 'create' => array(
  709. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  710. 'foreign_key' => array('type' => 'integer', 'null' => false, 'default' => null),
  711. 'model' => array('type' => 'varchar', 'null' => false, 'default' => null),
  712. 'value' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => null),
  713. 'created' => array('type' => 'datetime', 'null' => false, 'default' => null),
  714. 'modified' => array('type' => 'datetime', 'null' => false, 'default' => null),
  715. 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)),
  716. 'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM')
  717. )
  718. )
  719. );
  720. $this->assertEquals($expected, $compare);
  721. }
  722. /**
  723. * test comparing '' and null and making sure they are different.
  724. *
  725. * @return void
  726. */
  727. public function testCompareEmptyStringAndNull() {
  728. $One = new CakeSchema(array(
  729. 'posts' => array(
  730. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  731. 'name' => array('type' => 'string', 'null' => false, 'default' => '')
  732. )
  733. ));
  734. $Two = new CakeSchema(array(
  735. 'posts' => array(
  736. 'id' => array('type' => 'integer', 'null' => false, 'default' => null, 'key' => 'primary'),
  737. 'name' => array('type' => 'string', 'null' => false, 'default' => null)
  738. )
  739. ));
  740. $compare = $One->compare($Two);
  741. $expected = array(
  742. 'posts' => array(
  743. 'change' => array(
  744. 'name' => array('type' => 'string', 'null' => false, 'default' => null)
  745. )
  746. )
  747. );
  748. $this->assertEquals($expected, $compare);
  749. }
  750. /**
  751. * Test comparing tableParameters and indexes.
  752. *
  753. * @return void
  754. */
  755. public function testTableParametersAndIndexComparison() {
  756. $old = array(
  757. 'posts' => array(
  758. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  759. 'author_id' => array('type' => 'integer', 'null' => false),
  760. 'title' => array('type' => 'string', 'null' => false),
  761. 'indexes' => array(
  762. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  763. ),
  764. 'tableParameters' => array(
  765. 'charset' => 'latin1',
  766. 'collate' => 'latin1_general_ci'
  767. )
  768. ),
  769. 'comments' => array(
  770. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  771. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  772. 'comment' => array('type' => 'text'),
  773. 'indexes' => array(
  774. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  775. 'post_id' => array('column' => 'post_id'),
  776. ),
  777. 'tableParameters' => array(
  778. 'engine' => 'InnoDB',
  779. 'charset' => 'latin1',
  780. 'collate' => 'latin1_general_ci'
  781. )
  782. )
  783. );
  784. $new = array(
  785. 'posts' => array(
  786. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  787. 'author_id' => array('type' => 'integer', 'null' => false),
  788. 'title' => array('type' => 'string', 'null' => false),
  789. 'indexes' => array(
  790. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  791. 'author_id' => array('column' => 'author_id'),
  792. ),
  793. 'tableParameters' => array(
  794. 'charset' => 'utf8',
  795. 'collate' => 'utf8_general_ci',
  796. 'engine' => 'MyISAM'
  797. )
  798. ),
  799. 'comments' => array(
  800. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  801. 'post_id' => array('type' => 'integer', 'null' => false, 'default' => 0),
  802. 'comment' => array('type' => 'text'),
  803. 'indexes' => array(
  804. 'PRIMARY' => array('column' => 'id', 'unique' => true),
  805. ),
  806. 'tableParameters' => array(
  807. 'charset' => 'utf8',
  808. 'collate' => 'utf8_general_ci'
  809. )
  810. )
  811. );
  812. $compare = $this->Schema->compare($old, $new);
  813. $expected = array(
  814. 'posts' => array(
  815. 'add' => array(
  816. 'indexes' => array('author_id' => array('column' => 'author_id')),
  817. ),
  818. 'change' => array(
  819. 'tableParameters' => array(
  820. 'charset' => 'utf8',
  821. 'collate' => 'utf8_general_ci',
  822. 'engine' => 'MyISAM'
  823. )
  824. )
  825. ),
  826. 'comments' => array(
  827. 'drop' => array(
  828. 'indexes' => array('post_id' => array('column' => 'post_id')),
  829. ),
  830. 'change' => array(
  831. 'tableParameters' => array(
  832. 'charset' => 'utf8',
  833. 'collate' => 'utf8_general_ci',
  834. )
  835. )
  836. )
  837. );
  838. $this->assertEquals($expected, $compare);
  839. }
  840. /**
  841. * Test comparing with field changed from VARCHAR to DATETIME
  842. *
  843. * @return void
  844. */
  845. public function testCompareVarcharToDatetime() {
  846. $old = array(
  847. 'posts' => array(
  848. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  849. 'author_id' => array('type' => 'integer', 'null' => false),
  850. 'title' => array('type' => 'string', 'null' => true, 'length' => 45),
  851. 'indexes' => array(
  852. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  853. ),
  854. 'tableParameters' => array(
  855. 'charset' => 'latin1',
  856. 'collate' => 'latin1_general_ci'
  857. )
  858. ),
  859. );
  860. $new = array(
  861. 'posts' => array(
  862. 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'),
  863. 'author_id' => array('type' => 'integer', 'null' => false),
  864. 'title' => array('type' => 'datetime', 'null' => false),
  865. 'indexes' => array(
  866. 'PRIMARY' => array('column' => 'id', 'unique' => true)
  867. ),
  868. 'tableParameters' => array(
  869. 'charset' => 'latin1',
  870. 'collate' => 'latin1_general_ci'
  871. )
  872. ),
  873. );
  874. $compare = $this->Schema->compare($old, $new);
  875. $expected = array(
  876. 'posts' => array(
  877. 'change' => array(
  878. 'title' => array(
  879. 'type' => 'datetime',
  880. 'null' => false,
  881. )
  882. )
  883. ),
  884. );
  885. $this->assertEquals($expected, $compare, 'Invalid SQL, datetime does not have length');
  886. }
  887. /**
  888. * testSchemaLoading method
  889. *
  890. * @return void
  891. */
  892. public function testSchemaLoading() {
  893. $Other = $this->Schema->load(array('name' => 'MyOtherApp', 'path' => TMP . 'tests'));
  894. $this->assertEquals('MyOtherApp', $Other->name);
  895. $this->assertEquals($Other->tables, $this->Schema->tables);
  896. }
  897. /**
  898. * test loading schema files inside of plugins.
  899. *
  900. * @return void
  901. */
  902. public function testSchemaLoadingFromPlugin() {
  903. App::build(array(
  904. 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS)
  905. ));
  906. CakePlugin::load('TestPlugin');
  907. $Other = $this->Schema->load(array('name' => 'TestPluginApp', 'plugin' => 'TestPlugin'));
  908. $this->assertEquals('TestPluginApp', $Other->name);
  909. $this->assertEquals(array('test_plugin_acos'), array_keys($Other->tables));
  910. App::build();
  911. }
  912. /**
  913. * testSchemaCreateTable method
  914. *
  915. * @return void
  916. */
  917. public function testSchemaCreateTable() {
  918. $db = ConnectionManager::getDataSource('test');
  919. $db->cacheSources = false;
  920. $Schema = new CakeSchema(array(
  921. 'connection' => 'test',
  922. 'testdescribes' => array(
  923. 'id' => array('type' => 'integer', 'key' => 'primary'),
  924. 'int_null' => array('type' => 'integer', 'null' => true),
  925. 'int_not_null' => array('type' => 'integer', 'null' => false),
  926. ),
  927. ));
  928. $sql = $db->createSchema($Schema);
  929. $col = $Schema->tables['testdescribes']['int_null'];
  930. $col['name'] = 'int_null';
  931. $column = $this->db->buildColumn($col);
  932. $this->assertRegExp('/' . preg_quote($column, '/') . '/', $sql);
  933. $col = $Schema->tables['testdescribes']['int_not_null'];
  934. $col['name'] = 'int_not_null';
  935. $column = $this->db->buildColumn($col);
  936. $this->assertRegExp('/' . preg_quote($column, '/') . '/', $sql);
  937. }
  938. }