Overview

Packages

  • application
    • commands
    • components
      • actions
      • filters
      • leftWidget
      • permissions
      • sortableWidget
      • util
      • webupdater
      • x2flow
        • actions
        • triggers
      • X2GridView
      • X2Settings
    • controllers
    • models
      • embedded
    • modules
      • accounts
        • controllers
        • models
      • actions
        • controllers
        • models
      • calendar
        • controllers
        • models
      • charts
        • models
      • contacts
        • controllers
        • models
      • docs
        • components
        • controllers
        • models
      • groups
        • controllers
        • models
      • marketing
        • components
        • controllers
        • models
      • media
        • controllers
        • models
      • mobile
        • components
      • opportunities
        • controllers
        • models
      • products
        • controllers
        • models
      • quotes
        • controllers
        • models
      • services
        • controllers
        • models
      • template
        • models
      • users
        • controllers
        • models
      • workflow
        • controllers
        • models
      • x2Leads
        • controllers
        • models
  • Net
  • None
  • PHP
  • system
    • base
    • caching
      • dependencies
    • collections
    • console
    • db
      • ar
      • schema
        • cubrid
        • mssql
        • mysql
        • oci
        • pgsql
        • sqlite
    • i18n
      • gettext
    • logging
    • test
    • utils
    • validators
    • web
      • actions
      • auth
      • filters
      • form
      • helpers
      • renderers
      • services
      • widgets
        • captcha
        • pagers
  • Text
    • Highlighter
  • zii
    • behaviors
    • widgets
      • grid
      • jui

Classes

  • CDbFixtureManager
  • CDbTestCase
  • CTestCase
  • CWebTestCase
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * This file contains the CDbFixtureManager class.
  4:  *
  5:  * @author Qiang Xue <qiang.xue@gmail.com>
  6:  * @link http://www.yiiframework.com/
  7:  * @copyright 2008-2013 Yii Software LLC
  8:  * @license http://www.yiiframework.com/license/
  9:  */
 10: 
 11: /**
 12:  * CDbFixtureManager manages database fixtures during tests.
 13:  *
 14:  * A fixture represents a list of rows for a specific table. For a test method,
 15:  * using a fixture means that at the beginning of the method, the table has and only
 16:  * has the rows that are given in the fixture. Therefore, the table's state is
 17:  * predictable.
 18:  *
 19:  * A fixture is represented as a PHP script whose name (without suffix) is the
 20:  * same as the table name (if schema name is needed, it should be prefixed to
 21:  * the table name). The PHP script returns an array representing a list of table
 22:  * rows. Each row is an associative array of column values indexed by column names.
 23:  *
 24:  * A fixture can be associated with an init script which sits under the same fixture
 25:  * directory and is named as "TableName.init.php". The init script is used to
 26:  * initialize the table before populating the fixture data into the table.
 27:  * If the init script does not exist, the table will be emptied.
 28:  *
 29:  * Fixtures must be stored under the {@link basePath} directory. The directory
 30:  * may contain a file named "init.php" which will be executed once to initialize
 31:  * the database. If this file is not found, all available fixtures will be loaded
 32:  * into the database.
 33:  *
 34:  * @property CDbConnection $dbConnection The database connection.
 35:  * @property array $fixtures The information of the available fixtures (table name => fixture file).
 36:  *
 37:  * @author Qiang Xue <qiang.xue@gmail.com>
 38:  * @package system.test
 39:  * @since 1.1
 40:  */
 41: class CDbFixtureManager extends CApplicationComponent
 42: {
 43:     /**
 44:      * @var string the name of the initialization script that would be executed before the whole test set runs.
 45:      * Defaults to 'init.php'. If the script does not exist, every table with a fixture file will be reset.
 46:      */
 47:     public $initScript='init.php';
 48:     /**
 49:      * @var string the suffix for fixture initialization scripts.
 50:      * If a table is associated with such a script whose name is TableName suffixed this property value,
 51:      * then the script will be executed each time before the table is reset.
 52:      */
 53:     public $initScriptSuffix='.init.php';
 54:     /**
 55:      * @var string the base path containing all fixtures. Defaults to null, meaning
 56:      * the path 'protected/tests/fixtures'.
 57:      */
 58:     public $basePath;
 59:     /**
 60:      * @var string the ID of the database connection. Defaults to 'db'.
 61:      * Note, data in this database may be deleted or modified during testing.
 62:      * Make sure you have a backup database.
 63:      */
 64:     public $connectionID='db';
 65:     /**
 66:      * @var array list of database schemas that the test tables may reside in. Defaults to
 67:      * array(''), meaning using the default schema (an empty string refers to the
 68:      * default schema). This property is mainly used when turning on and off integrity checks
 69:      * so that fixture data can be populated into the database without causing problem.
 70:      */
 71:     public $schemas=array('');
 72: 
 73:     private $_db;
 74:     private $_fixtures;
 75:     /* x2modstart */ 
 76:     // private changed to protected
 77:     protected $_rows;               // fixture name, row alias => row
 78:     protected $_records;            // fixture name, row alias => record (or class name)
 79:     /* x2modend */ 
 80: 
 81: 
 82:     /**
 83:      * Initializes this application component.
 84:      */
 85:     public function init()
 86:     {
 87:         parent::init();
 88:         if($this->basePath===null)
 89:             $this->basePath=Yii::getPathOfAlias('application.tests.fixtures');
 90:         $this->prepare();
 91:     }
 92: 
 93:     /**
 94:      * Returns the database connection used to load fixtures.
 95:      * @throws CException if {@link connectionID} application component is invalid
 96:      * @return CDbConnection the database connection
 97:      */
 98:     public function getDbConnection()
 99:     {
100:         if($this->_db===null)
101:         {
102:             $this->_db=Yii::app()->getComponent($this->connectionID);
103:             if(!$this->_db instanceof CDbConnection)
104:                 throw new CException(Yii::t('yii','CDbTestFixture.connectionID "{id}" is invalid. Please make sure it refers to the ID of a CDbConnection application component.',
105:                     array('{id}'=>$this->connectionID)));
106:         }
107:         return $this->_db;
108:     }
109: 
110:     /**
111:      * Prepares the fixtures for the whole test.
112:      * This method is invoked in {@link init}. It executes the database init script
113:      * if it exists. Otherwise, it will load all available fixtures.
114:      */
115:     public function prepare()
116:     {
117:         $initFile=$this->basePath . DIRECTORY_SEPARATOR . $this->initScript;
118: 
119:         $this->checkIntegrity(false);
120: 
121:         if(is_file($initFile))
122:             require($initFile);
123:         else
124:         {
125:             foreach($this->getFixtures() as $tableName=>$fixturePath)
126:             {
127:                 $this->resetTable($tableName);
128:                 $this->loadFixture($tableName);
129:             }
130:         }
131:         $this->checkIntegrity(true);
132:     }
133: 
134:     /**
135:      * Resets the table to the state that it contains no fixture data.
136:      * If there is an init script named "tests/fixtures/TableName.init.php",
137:      * the script will be executed.
138:      * Otherwise, {@link truncateTable} will be invoked to delete all rows in the table
139:      * and reset primary key sequence, if any.
140:      * @param string $tableName the table name
141:      */
142:     public function resetTable($tableName)
143:     {
144:         $initFile=$this->basePath . DIRECTORY_SEPARATOR . $tableName . $this->initScriptSuffix;
145:         if(is_file($initFile))
146:             require($initFile);
147:         else
148:             $this->truncateTable($tableName);
149:     }
150: 
151:     /**
152:      * Loads the fixture for the specified table.
153:      * This method will insert rows given in the fixture into the corresponding table.
154:      * The loaded rows will be returned by this method.
155:      * If the table has auto-incremental primary key, each row will contain updated primary key value.
156:      * If the fixture does not exist, this method will return false.
157:      * Note, you may want to call {@link resetTable} before calling this method
158:      * so that the table is emptied first.
159:      * @param string $tableName table name
160:      * @return array the loaded fixture rows indexed by row aliases (if any).
161:      * False is returned if the table does not have a fixture.
162:      */
163:     public function loadFixture($tableName)
164:     {
165:         $fileName=$this->basePath.DIRECTORY_SEPARATOR.$tableName.'.php';
166:         if(!is_file($fileName))
167:             return false;
168: 
169:         $rows=array();
170:         $schema=$this->getDbConnection()->getSchema();
171:         $builder=$schema->getCommandBuilder();
172:         $table=$schema->getTable($tableName);
173: 
174:         foreach(require($fileName) as $alias=>$row)
175:         {
176:             $builder->createInsertCommand($table,$row)->execute();
177:             $primaryKey=$table->primaryKey;
178:             if($table->sequenceName!==null)
179:             {
180:                 if(is_string($primaryKey) && !isset($row[$primaryKey]))
181:                     $row[$primaryKey]=$builder->getLastInsertID($table);
182:                 elseif(is_array($primaryKey))
183:                 {
184:                     foreach($primaryKey as $pk)
185:                     {
186:                         if(!isset($row[$pk]))
187:                         {
188:                             $row[$pk]=$builder->getLastInsertID($table);
189:                             break;
190:                         }
191:                     }
192:                 }
193:             }
194:             $rows[$alias]=$row;
195:         }
196:         return $rows;
197:     }
198: 
199:     /**
200:      * Returns the information of the available fixtures.
201:      * This method will search for all PHP files under {@link basePath}.
202:      * If a file's name is the same as a table name, it is considered to be the fixture data for that table.
203:      * @return array the information of the available fixtures (table name => fixture file)
204:      */
205:     public function getFixtures()
206:     {
207:         if($this->_fixtures===null)
208:         {
209:             $this->_fixtures=array();
210:             $schema=$this->getDbConnection()->getSchema();
211:             $folder=opendir($this->basePath);
212:             $suffixLen=strlen($this->initScriptSuffix);
213:             while($file=readdir($folder))
214:             {
215:                 if($file==='.' || $file==='..' || $file===$this->initScript)
216:                     continue;
217:                 $path=$this->basePath.DIRECTORY_SEPARATOR.$file;
218:                 if(substr($file,-4)==='.php' && is_file($path) && substr($file,-$suffixLen)!==$this->initScriptSuffix)
219:                 {
220:                     $tableName=substr($file,0,-4);
221:                     if($schema->getTable($tableName)!==null)
222:                         $this->_fixtures[$tableName]=$path;
223:                 }
224:             }
225:             closedir($folder);
226:         }
227:         return $this->_fixtures;
228:     }
229: 
230:     /**
231:      * Enables or disables database integrity check.
232:      * This method may be used to temporarily turn off foreign constraints check.
233:      * @param boolean $check whether to enable database integrity check
234:      */
235:     public function checkIntegrity($check)
236:     {
237:         foreach($this->schemas as $schema)
238:             $this->getDbConnection()->getSchema()->checkIntegrity($check,$schema);
239:     }
240: 
241:     /**
242:      * Removes all rows from the specified table and resets its primary key sequence, if any.
243:      * You may need to call {@link checkIntegrity} to turn off integrity check temporarily
244:      * before you call this method.
245:      * @param string $tableName the table name
246:      * @throws CException if given table does not exist
247:      */
248:     public function truncateTable($tableName)
249:     {
250:         $db=$this->getDbConnection();
251:         $schema=$db->getSchema();
252:         if(($table=$schema->getTable($tableName))!==null)
253:         {
254:             $db->createCommand('DELETE FROM '.$table->rawName)->execute();
255:             $schema->resetSequence($table,1);
256:         }
257:         else
258:             throw new CException("Table '$tableName' does not exist.");
259:     }
260: 
261:     /**
262:      * Truncates all tables in the specified schema.
263:      * You may need to call {@link checkIntegrity} to turn off integrity check temporarily
264:      * before you call this method.
265:      * @param string $schema the schema name. Defaults to empty string, meaning the default database schema.
266:      * @see truncateTable
267:      */
268:     public function truncateTables($schema='')
269:     {
270:         $tableNames=$this->getDbConnection()->getSchema()->getTableNames($schema);
271:         foreach($tableNames as $tableName)
272:             $this->truncateTable($tableName);
273:     }
274: 
275:     /**
276:      * Loads the specified fixtures.
277:      * For each fixture, the corresponding table will be reset first by calling
278:      * {@link resetTable} and then be populated with the fixture data.
279:      * The loaded fixture data may be later retrieved using {@link getRows}
280:      * and {@link getRecord}.
281:      * Note, if a table does not have fixture data, {@link resetTable} will still
282:      * be called to reset the table.
283:      * @param array $fixtures fixtures to be loaded. The array keys are fixture names,
284:      * and the array values are either AR class names or table names.
285:      * If table names, they must begin with a colon character (e.g. 'Post'
286:      * means an AR class, while ':Post' means a table name).
287:      */
288:     public function load($fixtures)
289:     {
290:         $schema=$this->getDbConnection()->getSchema();
291:         $schema->checkIntegrity(false);
292: 
293:         $this->_rows=array();
294:         $this->_records=array();
295:         foreach($fixtures as $fixtureName=>$tableName)
296:         {
297:             if($tableName[0]===':')
298:             {
299:                 $tableName=substr($tableName,1);
300:                 unset($modelClass);
301:             }
302:             else
303:             {
304:                 $modelClass=Yii::import($tableName,true);
305:                 $tableName=CActiveRecord::model($modelClass)->tableName();
306:             }
307:             if(($prefix=$this->getDbConnection()->tablePrefix)!==null)
308:                 $tableName=preg_replace('/{{(.*?)}}/',$prefix.'\1',$tableName);
309:             $this->resetTable($tableName);
310:             $rows=$this->loadFixture($tableName);
311:             if(is_array($rows) && is_string($fixtureName))
312:             {
313:                 $this->_rows[$fixtureName]=$rows;
314:                 if(isset($modelClass))
315:                 {
316:                     foreach(array_keys($rows) as $alias)
317:                         $this->_records[$fixtureName][$alias]=$modelClass;
318:                 }
319:             }
320:         }
321: 
322:         $schema->checkIntegrity(true);
323:     }
324: 
325:     /**
326:      * Returns the fixture data rows.
327:      * The rows will have updated primary key values if the primary key is auto-incremental.
328:      * @param string $name the fixture name
329:      * @return array the fixture data rows. False is returned if there is no such fixture data.
330:      */
331:     public function getRows($name)
332:     {
333:         if(isset($this->_rows[$name]))
334:             return $this->_rows[$name];
335:         else
336:             return false;
337:     }
338: 
339:     /**
340:      * Returns the specified ActiveRecord instance in the fixture data.
341:      * @param string $name the fixture name
342:      * @param string $alias the alias for the fixture data row
343:      * @return CActiveRecord the ActiveRecord instance. False is returned if there is no such fixture row.
344:      */
345:     public function getRecord($name,$alias)
346:     {
347:         if(isset($this->_records[$name][$alias]))
348:         {
349:             if(is_string($this->_records[$name][$alias]))
350:             {
351:                 $row=$this->_rows[$name][$alias];
352:                 $model=CActiveRecord::model($this->_records[$name][$alias]);
353:                 $key=$model->getTableSchema()->primaryKey;
354:                 if(is_string($key))
355:                     $pk=$row[$key];
356:                 else
357:                 {
358:                     foreach($key as $k)
359:                         $pk[$k]=$row[$k];
360:                 }
361:                 $this->_records[$name][$alias]=$model->findByPk($pk);
362:             }
363:             return $this->_records[$name][$alias];
364:         }
365:         else
366:             return false;
367:     }
368: }
369: 
API documentation generated by ApiGen 2.8.0