Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
16591 anikendra 1
<?php
2
/**
3
 * A factory class to manage the life cycle of test fixtures
4
 *
5
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
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://cakephp.org CakePHP(tm) Project
14
 * @package       Cake.TestSuite.Fixture
15
 * @since         CakePHP(tm) v 2.0
16
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
17
 */
18
 
19
App::uses('ConnectionManager', 'Model');
20
App::uses('ClassRegistry', 'Utility');
21
 
22
/**
23
 * A factory class to manage the life cycle of test fixtures
24
 *
25
 * @package       Cake.TestSuite.Fixture
26
 */
27
class CakeFixtureManager {
28
 
29
/**
30
 * Was this class already initialized?
31
 *
32
 * @var bool
33
 */
34
	protected $_initialized = false;
35
 
36
/**
37
 * Default datasource to use
38
 *
39
 * @var DataSource
40
 */
41
	protected $_db = null;
42
 
43
/**
44
 * Holds the fixture classes that where instantiated
45
 *
46
 * @var array
47
 */
48
	protected $_loaded = array();
49
 
50
/**
51
 * Holds the fixture classes that where instantiated indexed by class name
52
 *
53
 * @var array
54
 */
55
	protected $_fixtureMap = array();
56
 
57
/**
58
 * Inspects the test to look for unloaded fixtures and loads them
59
 *
60
 * @param CakeTestCase $test the test case to inspect
61
 * @return void
62
 */
63
	public function fixturize($test) {
64
		if (!$this->_initialized) {
65
			ClassRegistry::config(array('ds' => 'test', 'testing' => true));
66
		}
67
		if (empty($test->fixtures) || !empty($this->_processed[get_class($test)])) {
68
			$test->db = $this->_db;
69
			return;
70
		}
71
		$this->_initDb();
72
		$test->db = $this->_db;
73
		if (!is_array($test->fixtures)) {
74
			$test->fixtures = array_map('trim', explode(',', $test->fixtures));
75
		}
76
		if (isset($test->fixtures)) {
77
			$this->_loadFixtures($test->fixtures);
78
		}
79
 
80
		$this->_processed[get_class($test)] = true;
81
	}
82
 
83
/**
84
 * Initializes this class with a DataSource object to use as default for all fixtures
85
 *
86
 * @return void
87
 */
88
	protected function _initDb() {
89
		if ($this->_initialized) {
90
			return;
91
		}
92
		$db = ConnectionManager::getDataSource('test');
93
		$db->cacheSources = false;
94
		$this->_db = $db;
95
		$this->_initialized = true;
96
	}
97
 
98
/**
99
 * Parse the fixture path included in test cases, to get the fixture class name, and the
100
 * real fixture path including sub-directories
101
 * 
102
 * @param string $fixturePath the fixture path to parse
103
 * @return array containing fixture class name and optional additional path
104
 */
105
	protected function _parseFixturePath($fixturePath) {
106
		$pathTokenArray = explode('/', $fixturePath);
107
		$fixture = array_pop($pathTokenArray);
108
		$additionalPath = '';
109
		foreach ($pathTokenArray as $pathToken) {
110
			$additionalPath .= DS . $pathToken;
111
		}
112
		return array('fixture' => $fixture, 'additionalPath' => $additionalPath);
113
	}
114
 
115
/**
116
 * Looks for fixture files and instantiates the classes accordingly
117
 *
118
 * @param array $fixtures the fixture names to load using the notation {type}.{name}
119
 * @return void
120
 * @throws UnexpectedValueException when a referenced fixture does not exist.
121
 */
122
	protected function _loadFixtures($fixtures) {
123
		foreach ($fixtures as $fixture) {
124
			$fixtureFile = null;
125
			$fixtureIndex = $fixture;
126
			if (isset($this->_loaded[$fixture])) {
127
				continue;
128
			}
129
 
130
			if (strpos($fixture, 'core.') === 0) {
131
				$fixture = substr($fixture, strlen('core.'));
132
				$fixturePaths[] = CAKE . 'Test' . DS . 'Fixture';
133
			} elseif (strpos($fixture, 'app.') === 0) {
134
				$fixturePrefixLess = substr($fixture, strlen('app.'));
135
				$fixtureParsedPath = $this->_parseFixturePath($fixturePrefixLess);
136
				$fixture = $fixtureParsedPath['fixture'];
137
				$fixturePaths = array(
138
					TESTS . 'Fixture' . $fixtureParsedPath['additionalPath']
139
				);
140
			} elseif (strpos($fixture, 'plugin.') === 0) {
141
				$explodedFixture = explode('.', $fixture, 3);
142
				$pluginName = $explodedFixture[1];
143
				$fixtureParsedPath = $this->_parseFixturePath($explodedFixture[2]);
144
				$fixture = $fixtureParsedPath['fixture'];
145
				$fixturePaths = array(
146
					CakePlugin::path(Inflector::camelize($pluginName)) . 'Test' . DS . 'Fixture' . $fixtureParsedPath['additionalPath'],
147
					TESTS . 'Fixture' . $fixtureParsedPath['additionalPath']
148
				);
149
			} else {
150
				$fixturePaths = array(
151
					TESTS . 'Fixture',
152
					CAKE . 'Test' . DS . 'Fixture'
153
				);
154
			}
155
 
156
			$loaded = false;
157
			foreach ($fixturePaths as $path) {
158
				$className = Inflector::camelize($fixture);
159
				if (is_readable($path . DS . $className . 'Fixture.php')) {
160
					$fixtureFile = $path . DS . $className . 'Fixture.php';
161
					require_once $fixtureFile;
162
					$fixtureClass = $className . 'Fixture';
163
					$this->_loaded[$fixtureIndex] = new $fixtureClass();
164
					$this->_fixtureMap[$fixtureClass] = $this->_loaded[$fixtureIndex];
165
					$loaded = true;
166
					break;
167
				}
168
			}
169
 
170
			if (!$loaded) {
171
				$firstPath = str_replace(array(APP, CAKE_CORE_INCLUDE_PATH, ROOT), '', $fixturePaths[0] . DS . $className . 'Fixture.php');
172
				throw new UnexpectedValueException(__d('cake_dev', 'Referenced fixture class %s (%s) not found', $className, $firstPath));
173
			}
174
		}
175
	}
176
 
177
/**
178
 * Runs the drop and create commands on the fixtures if necessary.
179
 *
180
 * @param CakeTestFixture $fixture the fixture object to create
181
 * @param DataSource $db the datasource instance to use
182
 * @param bool $drop whether drop the fixture if it is already created or not
183
 * @return void
184
 */
185
	protected function _setupTable($fixture, $db = null, $drop = true) {
186
		if (!$db) {
187
			if (!empty($fixture->useDbConfig)) {
188
				$db = ConnectionManager::getDataSource($fixture->useDbConfig);
189
			} else {
190
				$db = $this->_db;
191
			}
192
		}
193
		if (!empty($fixture->created) && in_array($db->configKeyName, $fixture->created)) {
194
			return;
195
		}
196
 
197
		$sources = (array)$db->listSources();
198
		$table = $db->config['prefix'] . $fixture->table;
199
		$exists = in_array($table, $sources);
200
 
201
		if ($drop && $exists) {
202
			$fixture->drop($db);
203
			$fixture->create($db);
204
		} elseif (!$exists) {
205
			$fixture->create($db);
206
		} else {
207
			$fixture->created[] = $db->configKeyName;
208
		}
209
	}
210
 
211
/**
212
 * Creates the fixtures tables and inserts data on them.
213
 *
214
 * @param CakeTestCase $test the test to inspect for fixture loading
215
 * @return void
216
 */
217
	public function load(CakeTestCase $test) {
218
		if (empty($test->fixtures)) {
219
			return;
220
		}
221
		$fixtures = $test->fixtures;
222
		if (empty($fixtures) || !$test->autoFixtures) {
223
			return;
224
		}
225
 
226
		foreach ($fixtures as $f) {
227
			if (!empty($this->_loaded[$f])) {
228
				$fixture = $this->_loaded[$f];
229
				$db = ConnectionManager::getDataSource($fixture->useDbConfig);
230
				$db->begin();
231
				$this->_setupTable($fixture, $db, $test->dropTables);
232
				$fixture->truncate($db);
233
				$fixture->insert($db);
234
				$db->commit();
235
			}
236
		}
237
	}
238
 
239
/**
240
 * Truncates the fixtures tables
241
 *
242
 * @param CakeTestCase $test the test to inspect for fixture unloading
243
 * @return void
244
 */
245
	public function unload(CakeTestCase $test) {
246
		$fixtures = !empty($test->fixtures) ? $test->fixtures : array();
247
		foreach (array_reverse($fixtures) as $f) {
248
			if (isset($this->_loaded[$f])) {
249
				$fixture = $this->_loaded[$f];
250
				if (!empty($fixture->created)) {
251
					foreach ($fixture->created as $ds) {
252
						$db = ConnectionManager::getDataSource($ds);
253
						$fixture->truncate($db);
254
					}
255
				}
256
			}
257
		}
258
	}
259
 
260
/**
261
 * Creates a single fixture table and loads data into it.
262
 *
263
 * @param string $name of the fixture
264
 * @param DataSource $db DataSource instance or leave null to get DataSource from the fixture
265
 * @param bool $dropTables Whether or not tables should be dropped and re-created.
266
 * @return void
267
 * @throws UnexpectedValueException if $name is not a previously loaded class
268
 */
269
	public function loadSingle($name, $db = null, $dropTables = true) {
270
		$name .= 'Fixture';
271
		if (isset($this->_fixtureMap[$name])) {
272
			$fixture = $this->_fixtureMap[$name];
273
			if (!$db) {
274
				$db = ConnectionManager::getDataSource($fixture->useDbConfig);
275
			}
276
			$this->_setupTable($fixture, $db, $dropTables);
277
			$fixture->truncate($db);
278
			$fixture->insert($db);
279
		} else {
280
			throw new UnexpectedValueException(__d('cake_dev', 'Referenced fixture class %s not found', $name));
281
		}
282
	}
283
 
284
/**
285
 * Drop all fixture tables loaded by this class
286
 *
287
 * This will also close the session, as failing to do so will cause
288
 * fatal errors with database sessions.
289
 *
290
 * @return void
291
 */
292
	public function shutDown() {
293
		if (session_id()) {
294
			session_write_close();
295
		}
296
		foreach ($this->_loaded as $fixture) {
297
			if (!empty($fixture->created)) {
298
				foreach ($fixture->created as $ds) {
299
					$db = ConnectionManager::getDataSource($ds);
300
					$fixture->drop($db);
301
				}
302
			}
303
		}
304
	}
305
 
306
}