PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/cakephp/cakephp/src/TestSuite/Fixture/TestFixture.php

https://gitlab.com/vannh/portal_training
PHP | 325 lines | 181 code | 26 blank | 118 comment | 21 complexity | 72da94ac2f2a40fac9e7afcb97fe2d7b MD5 | raw file
  1. <?php
  2. /**
  3. * CakePHP(tm) Tests <http://book.cakephp.org/2.0/en/development/testing.html>
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * For full copyright and license information, please see the LICENSE.txt
  8. * Redistributions of files must retain the above copyright notice
  9. *
  10. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  11. * @since 1.2.0
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\TestSuite\Fixture;
  15. use Cake\Core\Exception\Exception;
  16. use Cake\Database\Connection;
  17. use Cake\Database\Schema\Table;
  18. use Cake\Datasource\ConnectionManager;
  19. use Cake\Log\Log;
  20. use Cake\Utility\Inflector;
  21. /**
  22. * Cake TestFixture is responsible for building and destroying tables to be used
  23. * during testing.
  24. */
  25. class TestFixture
  26. {
  27. /**
  28. * Fixture Datasource
  29. *
  30. * @var string
  31. */
  32. public $connection = 'test';
  33. /**
  34. * Full Table Name
  35. *
  36. * @var string
  37. */
  38. public $table = null;
  39. /**
  40. * List of datasources where this fixture has been created
  41. *
  42. * @var array
  43. */
  44. public $created = [];
  45. /**
  46. * Fields / Schema for the fixture.
  47. *
  48. * This array should be compatible with Cake\Database\Schema\Table.
  49. * The `_constraints`, `_options` and `_indexes` keys are reserved for defining
  50. * constraints, options and indexes respectively.
  51. *
  52. * @var array
  53. */
  54. public $fields = [];
  55. /**
  56. * Configuration for importing fixture schema
  57. *
  58. * Accepts a `connection` and `table` key, to define
  59. * which table and which connection contain the schema to be
  60. * imported.
  61. *
  62. * @var array
  63. */
  64. public $import = null;
  65. /**
  66. * Fixture records to be inserted.
  67. *
  68. * @var array
  69. */
  70. public $records = [];
  71. /**
  72. * The Cake\Database\Schema\Table for this fixture.
  73. *
  74. * @var \Cake\Database\Schema\Table
  75. */
  76. protected $_schema;
  77. /**
  78. * Instantiate the fixture.
  79. *
  80. * @throws \Cake\Core\Exception\Exception on invalid datasource usage.
  81. */
  82. public function __construct()
  83. {
  84. if (!empty($this->connection)) {
  85. $connection = $this->connection;
  86. if (strpos($connection, 'test') !== 0) {
  87. $message = sprintf(
  88. 'Invalid datasource name "%s" for "%s" fixture. Fixture datasource names must begin with "test".',
  89. $connection,
  90. $this->name
  91. );
  92. throw new Exception($message);
  93. }
  94. }
  95. $this->init();
  96. }
  97. /**
  98. * Initialize the fixture.
  99. *
  100. * @return void
  101. * @throws \Cake\ORM\Exception\MissingTableClassException When importing from a table that does not exist.
  102. */
  103. public function init()
  104. {
  105. if ($this->table === null) {
  106. list(, $class) = namespaceSplit(get_class($this));
  107. preg_match('/^(.*)Fixture$/', $class, $matches);
  108. $table = $class;
  109. if (isset($matches[1])) {
  110. $table = $matches[1];
  111. }
  112. $this->table = Inflector::tableize($table);
  113. }
  114. if (empty($this->import) && !empty($this->fields)) {
  115. $this->_schemaFromFields();
  116. }
  117. if (!empty($this->import)) {
  118. $this->_schemaFromImport();
  119. }
  120. }
  121. /**
  122. * Build the fixtures table schema from the fields property.
  123. *
  124. * @return void
  125. */
  126. protected function _schemaFromFields()
  127. {
  128. $this->_schema = new Table($this->table);
  129. foreach ($this->fields as $field => $data) {
  130. if ($field === '_constraints' || $field === '_indexes' || $field === '_options') {
  131. continue;
  132. }
  133. $this->_schema->addColumn($field, $data);
  134. }
  135. if (!empty($this->fields['_constraints'])) {
  136. foreach ($this->fields['_constraints'] as $name => $data) {
  137. $this->_schema->addConstraint($name, $data);
  138. }
  139. }
  140. if (!empty($this->fields['_indexes'])) {
  141. foreach ($this->fields['_indexes'] as $name => $data) {
  142. $this->_schema->addIndex($name, $data);
  143. }
  144. }
  145. if (!empty($this->fields['_options'])) {
  146. $this->_schema->options($this->fields['_options']);
  147. }
  148. }
  149. /**
  150. * Build fixture schema from a table in another datasource.
  151. *
  152. * @return void
  153. * @throws \Cake\Core\Exception\Exception when trying to import from an empty table.
  154. */
  155. protected function _schemaFromImport()
  156. {
  157. if (!is_array($this->import)) {
  158. return;
  159. }
  160. $import = array_merge(
  161. ['connection' => 'default', 'table' => null],
  162. $this->import
  163. );
  164. if (empty($import['table'])) {
  165. throw new Exception('Cannot import from undefined table.');
  166. } else {
  167. $this->table = $import['table'];
  168. }
  169. $db = ConnectionManager::get($import['connection'], false);
  170. $schemaCollection = $db->schemaCollection();
  171. $table = $schemaCollection->describe($import['table']);
  172. $this->_schema = $table;
  173. }
  174. /**
  175. * Get/Set the Cake\Database\Schema\Table instance used by this fixture.
  176. *
  177. * @param \Cake\Database\Schema\Table $schema The table to set.
  178. * @return void|\Cake\Database\Schema\Table
  179. */
  180. public function schema(Table $schema = null)
  181. {
  182. if ($schema) {
  183. $this->_schema = $schema;
  184. return;
  185. }
  186. return $this->_schema;
  187. }
  188. /**
  189. * Run before all tests execute, should return SQL statement to create table for this fixture could be executed successfully.
  190. *
  191. * @param Connection $db An instance of the database object used to create the fixture table
  192. * @return bool True on success, false on failure
  193. */
  194. public function create(Connection $db)
  195. {
  196. if (empty($this->_schema)) {
  197. return false;
  198. }
  199. try {
  200. $queries = $this->_schema->createSql($db);
  201. foreach ($queries as $query) {
  202. $db->execute($query)->closeCursor();
  203. }
  204. $this->created[] = $db->configName();
  205. } catch (\Exception $e) {
  206. $msg = sprintf(
  207. 'Fixture creation for "%s" failed "%s"',
  208. $this->table,
  209. $e->getMessage()
  210. );
  211. Log::error($msg);
  212. trigger_error($msg, E_USER_WARNING);
  213. return false;
  214. }
  215. return true;
  216. }
  217. /**
  218. * Run after all tests executed, should return SQL statement to drop table for this fixture.
  219. *
  220. * @param Connection $db An instance of the database object used to create the fixture table
  221. * @return bool True on success, false on failure
  222. */
  223. public function drop(Connection $db)
  224. {
  225. if (empty($this->_schema)) {
  226. return false;
  227. }
  228. try {
  229. $sql = $this->_schema->dropSql($db);
  230. foreach ($sql as $stmt) {
  231. $db->execute($stmt)->closeCursor();
  232. }
  233. $this->created = array_diff($this->created, [$db->configName()]);
  234. } catch (\Exception $e) {
  235. return false;
  236. }
  237. return true;
  238. }
  239. /**
  240. * Run before each tests is executed, should return a set of SQL statements to insert records for the table
  241. * of this fixture could be executed successfully.
  242. *
  243. * @param Connection $db An instance of the database into which the records will be inserted
  244. * @return bool on success or if there are no records to insert, or false on failure
  245. */
  246. public function insert(Connection $db)
  247. {
  248. if (isset($this->records) && !empty($this->records)) {
  249. list($fields, $values, $types) = $this->_getRecords();
  250. $query = $db->newQuery()
  251. ->insert($fields, $types)
  252. ->into($this->table);
  253. foreach ($values as $row) {
  254. $query->values($row);
  255. }
  256. $statement = $query->execute();
  257. $statement->closeCursor();
  258. return $statement;
  259. }
  260. return true;
  261. }
  262. /**
  263. * Converts the internal records into data used to generate a query.
  264. *
  265. * @return array
  266. */
  267. protected function _getRecords()
  268. {
  269. $fields = $values = $types = [];
  270. $columns = $this->_schema->columns();
  271. foreach ($this->records as $record) {
  272. $fields = array_merge($fields, array_intersect(array_keys($record), $columns));
  273. }
  274. $fields = array_values(array_unique($fields));
  275. foreach ($fields as $field) {
  276. $types[$field] = $this->_schema->column($field)['type'];
  277. }
  278. $default = array_fill_keys($fields, null);
  279. foreach ($this->records as $record) {
  280. $values[] = array_merge($default, $record);
  281. }
  282. return [$fields, $values, $types];
  283. }
  284. /**
  285. * Truncates the current fixture. Can be overwritten by classes extending
  286. * CakeFixture to trigger other events before / after truncate.
  287. *
  288. * @param Connection $db A reference to a db instance
  289. * @return bool
  290. */
  291. public function truncate(Connection $db)
  292. {
  293. $sql = $this->_schema->truncateSql($db);
  294. foreach ($sql as $stmt) {
  295. $db->execute($stmt)->closeCursor();
  296. }
  297. return true;
  298. }
  299. }