CakeSchemaTest.php 29 KB

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