統計
| ブランチ: | リビジョン:

pictcode / lib / Cake / TestSuite / Fixture / CakeTestFixture.php @ 635eef61

履歴 | 表示 | アノテート | ダウンロード (9.478 KB)

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
 * @link          http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests
12
 * @package       Cake.TestSuite.Fixture
13
 * @since         CakePHP(tm) v 1.2.0.4667
14
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
15
 */
16

    
17
App::uses('CakeSchema', 'Model');
18

    
19
/**
20
 * CakeTestFixture is responsible for building and destroying tables to be used
21
 * during testing.
22
 *
23
 * @package       Cake.TestSuite.Fixture
24
 */
25
class CakeTestFixture {
26

    
27
/**
28
 * Name of the object
29
 *
30
 * @var string
31
 */
32
        public $name = null;
33

    
34
/**
35
 * CakePHP's DBO driver (e.g: DboMysql).
36
 *
37
 * @var object
38
 */
39
        public $db = null;
40

    
41
/**
42
 * Fixture Datasource
43
 *
44
 * @var string
45
 */
46
        public $useDbConfig = 'test';
47

    
48
/**
49
 * Full Table Name
50
 *
51
 * @var string
52
 */
53
        public $table = null;
54

    
55
/**
56
 * List of datasources where this fixture has been created
57
 *
58
 * @var array
59
 */
60
        public $created = array();
61

    
62
/**
63
 * Fields / Schema for the fixture.
64
 * This array should match the output of Model::schema()
65
 *
66
 * @var array
67
 */
68
        public $fields = array();
69

    
70
/**
71
 * Fixture records to be inserted.
72
 *
73
 * @var array
74
 */
75
        public $records = array();
76

    
77
/**
78
 * The primary key for the table this fixture represents.
79
 *
80
 * @var string
81
 */
82
        public $primaryKey = null;
83

    
84
/**
85
 * Fixture data can be stored in memory by default.
86
 * When table is created for a fixture the MEMORY engine is used
87
 * where possible. Set $canUseMemory to false if you don't want this.
88
 *
89
 * @var bool
90
 */
91
        public $canUseMemory = true;
92

    
93
/**
94
 * Instantiate the fixture.
95
 *
96
 * @throws CakeException on invalid datasource usage.
97
 */
98
        public function __construct() {
99
                if ($this->name === null) {
100
                        if (preg_match('/^(.*)Fixture$/', get_class($this), $matches)) {
101
                                $this->name = $matches[1];
102
                        } else {
103
                                $this->name = get_class($this);
104
                        }
105
                }
106
                $connection = 'test';
107
                if (!empty($this->useDbConfig)) {
108
                        $connection = $this->useDbConfig;
109
                        if (strpos($connection, 'test') !== 0) {
110
                                $message = __d(
111
                                        'cake_dev',
112
                                        'Invalid datasource name "%s" for "%s" fixture. Fixture datasource names must begin with "test".',
113
                                        $connection,
114
                                        $this->name
115
                                );
116
                                throw new CakeException($message);
117
                        }
118
                }
119
                $this->Schema = new CakeSchema(array('name' => 'TestSuite', 'connection' => $connection));
120
                $this->init();
121
        }
122

    
123
/**
124
 * Initialize the fixture.
125
 *
126
 * @return void
127
 * @throws MissingModelException Whe importing from a model that does not exist.
128
 */
129
        public function init() {
130
                if (isset($this->import) && (is_string($this->import) || is_array($this->import))) {
131
                        $import = array_merge(
132
                                array('connection' => 'default', 'records' => false),
133
                                is_array($this->import) ? $this->import : array('model' => $this->import)
134
                        );
135

    
136
                        $this->Schema->connection = $import['connection'];
137
                        if (isset($import['model'])) {
138
                                list($plugin, $modelClass) = pluginSplit($import['model'], true);
139
                                App::uses($modelClass, $plugin . 'Model');
140
                                if (!class_exists($modelClass)) {
141
                                        throw new MissingModelException(array('class' => $modelClass));
142
                                }
143
                                $model = new $modelClass(null, null, $import['connection']);
144
                                $db = $model->getDataSource();
145
                                if (empty($model->tablePrefix)) {
146
                                        $model->tablePrefix = $db->config['prefix'];
147
                                }
148
                                $this->fields = $model->schema(true);
149
                                $this->fields[$model->primaryKey]['key'] = 'primary';
150
                                $this->table = $db->fullTableName($model, false, false);
151
                                $this->primaryKey = $model->primaryKey;
152
                                ClassRegistry::config(array('ds' => 'test'));
153
                                ClassRegistry::flush();
154
                        } elseif (isset($import['table'])) {
155
                                $model = new Model(null, $import['table'], $import['connection']);
156
                                $db = ConnectionManager::getDataSource($import['connection']);
157
                                $db->cacheSources = false;
158
                                $model->useDbConfig = $import['connection'];
159
                                $model->name = Inflector::camelize(Inflector::singularize($import['table']));
160
                                $model->table = $import['table'];
161
                                $model->tablePrefix = $db->config['prefix'];
162
                                $this->fields = $model->schema(true);
163
                                $this->primaryKey = $model->primaryKey;
164
                                ClassRegistry::flush();
165
                        }
166

    
167
                        if (!empty($db->config['prefix']) && strpos($this->table, $db->config['prefix']) === 0) {
168
                                $this->table = str_replace($db->config['prefix'], '', $this->table);
169
                        }
170

    
171
                        if (isset($import['records']) && $import['records'] !== false && isset($model) && isset($db)) {
172
                                $this->records = array();
173
                                $query = array(
174
                                        'fields' => $db->fields($model, null, array_keys($this->fields)),
175
                                        'table' => $db->fullTableName($model),
176
                                        'alias' => $model->alias,
177
                                        'conditions' => array(),
178
                                        'order' => null,
179
                                        'limit' => null,
180
                                        'group' => null
181
                                );
182
                                $records = $db->fetchAll($db->buildStatement($query, $model), false, $model->alias);
183

    
184
                                if ($records !== false && !empty($records)) {
185
                                        $this->records = Hash::extract($records, '{n}.' . $model->alias);
186
                                }
187
                        }
188
                }
189

    
190
                if (!isset($this->table)) {
191
                        $this->table = Inflector::underscore(Inflector::pluralize($this->name));
192
                }
193

    
194
                if (!isset($this->primaryKey) && isset($this->fields['id'])) {
195
                        $this->primaryKey = 'id';
196
                }
197
        }
198

    
199
/**
200
 * Run before all tests execute, should return SQL statement to create table for this fixture could be executed successfully.
201
 *
202
 * @param DboSource $db An instance of the database object used to create the fixture table
203
 * @return bool True on success, false on failure
204
 */
205
        public function create($db) {
206
                if (!isset($this->fields) || empty($this->fields)) {
207
                        return false;
208
                }
209

    
210
                if (empty($this->fields['tableParameters']['engine'])) {
211
                        $canUseMemory = $this->canUseMemory;
212
                        foreach ($this->fields as $args) {
213

    
214
                                if (is_string($args)) {
215
                                        $type = $args;
216
                                } elseif (!empty($args['type'])) {
217
                                        $type = $args['type'];
218
                                } else {
219
                                        continue;
220
                                }
221

    
222
                                if (in_array($type, array('blob', 'text', 'binary'))) {
223
                                        $canUseMemory = false;
224
                                        break;
225
                                }
226
                        }
227

    
228
                        if ($canUseMemory) {
229
                                $this->fields['tableParameters']['engine'] = 'MEMORY';
230
                        }
231
                }
232
                $this->Schema->build(array($this->table => $this->fields));
233
                try {
234
                        $db->execute($db->createSchema($this->Schema), array('log' => false));
235
                        $this->created[] = $db->configKeyName;
236
                } catch (Exception $e) {
237
                        $msg = __d(
238
                                'cake_dev',
239
                                'Fixture creation for "%s" failed "%s"',
240
                                $this->table,
241
                                $e->getMessage()
242
                        );
243
                        CakeLog::error($msg);
244
                        trigger_error($msg, E_USER_WARNING);
245
                        return false;
246
                }
247
                return true;
248
        }
249

    
250
/**
251
 * Run after all tests executed, should return SQL statement to drop table for this fixture.
252
 *
253
 * @param DboSource $db An instance of the database object used to create the fixture table
254
 * @return bool True on success, false on failure
255
 */
256
        public function drop($db) {
257
                if (empty($this->fields)) {
258
                        return false;
259
                }
260
                $this->Schema->build(array($this->table => $this->fields));
261
                try {
262

    
263
                        $db->execute($db->dropSchema($this->Schema), array('log' => false));
264
                        $this->created = array_diff($this->created, array($db->configKeyName));
265
                } catch (Exception $e) {
266
                        return false;
267
                }
268
                return true;
269
        }
270

    
271
/**
272
 * Run before each tests is executed, should return a set of SQL statements to insert records for the table
273
 * of this fixture could be executed successfully.
274
 *
275
 * @param DboSource $db An instance of the database into which the records will be inserted
276
 * @return bool on success or if there are no records to insert, or false on failure
277
 * @throws CakeException if counts of values and fields do not match.
278
 */
279
        public function insert($db) {
280
                if (!isset($this->_insert)) {
281
                        $values = array();
282
                        if (isset($this->records) && !empty($this->records)) {
283
                                $fields = array();
284
                                foreach ($this->records as $record) {
285
                                        $fields = array_merge($fields, array_keys(array_intersect_key($record, $this->fields)));
286
                                }
287
                                $fields = array_unique($fields);
288
                                $default = array_fill_keys($fields, null);
289
                                foreach ($this->records as $record) {
290
                                        $mergeData = array_merge($default, $record);
291
                                        $merge = array_values($mergeData);
292
                                        if (count($fields) !== count($merge)) {
293

    
294
                                                $mergeFields = array_diff_key(array_keys($mergeData), $fields);
295

    
296
                                                $message = 'Fixture invalid: Count of fields does not match count of values in ' . get_class($this) . "\n";
297
                                                foreach ($mergeFields as $field) {
298
                                                        $message .= "The field '" . $field . "' is in the data fixture but not in the schema." . "\n";
299
                                                }
300

    
301
                                                throw new CakeException($message);
302
                                        }
303
                                        $values[] = $merge;
304
                                }
305
                                $nested = $db->useNestedTransactions;
306
                                $db->useNestedTransactions = false;
307
                                $result = $db->insertMulti($this->table, $fields, $values);
308
                                if ($this->primaryKey &&
309
                                        isset($this->fields[$this->primaryKey]['type']) &&
310
                                        in_array($this->fields[$this->primaryKey]['type'], array('integer', 'biginteger'))
311
                                ) {
312
                                        $db->resetSequence($this->table, $this->primaryKey);
313
                                }
314
                                $db->useNestedTransactions = $nested;
315
                                return $result;
316
                        }
317
                        return true;
318
                }
319
        }
320

    
321
/**
322
 * Truncates the current fixture. Can be overwritten by classes extending
323
 * CakeFixture to trigger other events before / after truncate.
324
 *
325
 * @param DboSource $db A reference to a db instance
326
 * @return bool
327
 */
328
        public function truncate($db) {
329
                $fullDebug = $db->fullDebug;
330
                $db->fullDebug = false;
331
                $return = $db->truncate($this->table);
332
                $db->fullDebug = $fullDebug;
333
                return $return;
334
        }
335

    
336
}