pictcode / lib / Cake / TestSuite / Fixture / CakeFixtureManager.php @ master
履歴 | 表示 | アノテート | ダウンロード (8.581 KB)
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 |
} |