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