Webylon 3.2 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • 1c
    • exchange
      • catalog
  • auth
  • Booking
  • building
    • company
  • cart
    • shipping
    • steppedcheckout
  • Catalog
    • monument
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • CliTestReporter
  • FunctionalTest
  • InstallerTest
  • JSTestRunner
  • PHPUnit_Framework_TestCase
  • SapphireTest
  • SapphireTestReporter
  • SapphireTestSuite
  • TestRunner
  • TestSession
  • TestSession_STResponseWrapper
  • TestViewer

Interfaces

  • TestOnly

Functions

  • hasPhpUnit
  1 <?php
  2 require_once 'TestRunner.php';
  3 if(hasPhpUnit()) {
  4 require_once 'PHPUnit/Framework.php';
  5 }
  6 
  7 /**
  8  * Test case class for the Sapphire framework.
  9  * Sapphire unit testing is based on PHPUnit, but provides a number of hooks into our data model that make it easier to work with.
 10  * 
 11  * @package sapphire
 12  * @subpackage testing
 13  */
 14 class SapphireTest extends PHPUnit_Framework_TestCase {
 15     /**
 16      * Path to fixture data for this test run.
 17      * If passed as an array, multiple fixture files will be loaded.
 18      * Please note that you won't be able to refer with "=>" notation
 19      * between the fixtures, they act independent of each other.
 20      * 
 21      * @var string|array
 22      */
 23     static $fixture_file = null;
 24     
 25     protected $originalMailer;
 26     protected $originalMemberPasswordValidator;
 27     protected $originalRequirements;
 28     protected $originalIsRunningTest;
 29     protected $originalTheme;
 30     protected $originalNestedURLsState;
 31     
 32     protected $mailer;
 33     
 34     protected static $is_running_test = false;
 35     
 36     /**
 37      * By default, setUp() does not require default records. Pass
 38      * class names in here, and the require/augment default records
 39      * function will be called on them.
 40      */
 41     protected $requireDefaultRecordsFrom = array();
 42     
 43     
 44     /**
 45      * A list of extensions that can't be applied during the execution of this run.  If they are
 46      * applied, they will be temporarily removed and a database migration called.
 47      * 
 48      * The keys of the are the classes that the extensions can't be applied the extensions to, and
 49      * the values are an array of illegal extensions on that class.
 50      */
 51     protected $illegalExtensions = array(
 52     );
 53 
 54     /**
 55      * A list of extensions that must be applied during the execution of this run.  If they are
 56      * not applied, they will be temporarily added and a database migration called.
 57      * 
 58      * The keys of the are the classes to apply the extensions to, and the values are an array
 59      * of illegal required extensions on that class.
 60      */
 61     protected $requiredExtensions = array(
 62     );
 63     
 64     /**
 65      * By default, the test database won't contain any DataObjects that have the interface TestOnly.
 66      * This variable lets you define additional TestOnly DataObjects to set up for this test.
 67      * Set it to an array of DataObject subclass names.
 68      */
 69     protected $extraDataObjects = array();
 70     
 71     /**
 72      * We need to disabling backing up of globals to avoid overriding
 73      * the few globals SilverStripe relies on, like $lang for the i18n subsystem.
 74      * 
 75      * @see http://sebastian-bergmann.de/archives/797-Global-Variables-and-PHPUnit.html
 76      */
 77     protected $backupGlobals = FALSE;
 78 
 79     /** 
 80      * Helper arrays for illegalExtensions/requiredExtensions code
 81      */
 82     private $extensionsToReapply = array(), $extensionsToRemove = array();
 83     
 84     public static function is_running_test() {
 85         return self::$is_running_test;
 86     }
 87     
 88     /**
 89      * @var array $fixtures Array of {@link YamlFixture} instances
 90      */
 91     protected $fixtures; 
 92     
 93     function setUp() {
 94         // Mark test as being run
 95         $this->originalIsRunningTest = self::$is_running_test;
 96         self::$is_running_test = true;
 97         
 98         // Remove password validation
 99         $this->originalMemberPasswordValidator = Member::password_validator();
100         $this->originalRequirements = Requirements::backend();
101         Member::set_password_validator(null);
102         Cookie::set_report_errors(false);
103         
104         RootURLController::reset();
105         Translatable::reset();
106         Versioned::reset();
107         DataObject::reset();
108         SiteTree::reset();
109         Controller::curr()->setSession(new Session(array()));
110         
111         $this->originalTheme = SSViewer::current_theme();
112         
113         // Save nested_urls state, so we can restore it later
114         $this->originalNestedURLsState = SiteTree::nested_urls();
115 
116         $className = get_class($this);
117         $fixtureFile = eval("return {$className}::\$fixture_file;");
118         
119         // Set up fixture
120         if($fixtureFile || !self::using_temp_db()) {
121             if(substr(DB::getConn()->currentDatabase(),0,5) != 'tmpdb') {
122                 //echo "Re-creating temp database... ";
123                 self::create_temp_db();
124                 //echo "done.\n";
125             }
126 
127             singleton('DataObject')->flushCache();
128             
129             self::empty_temp_db();
130             
131             foreach($this->requireDefaultRecordsFrom as $className) {
132                 $instance = singleton($className);
133                 if (method_exists($instance, 'requireDefaultRecords')) $instance->requireDefaultRecords();
134                 if (method_exists($instance, 'augmentDefaultRecords')) $instance->augmentDefaultRecords();
135             }
136 
137             if($fixtureFile) {
138                 $fixtureFiles = (is_array($fixtureFile)) ? $fixtureFile : array($fixtureFile);
139 
140                 $i = 0;
141                 foreach($fixtureFiles as $fixtureFilePath) {
142                     $fixture = new YamlFixture($fixtureFilePath);
143                     $fixture->saveIntoDatabase();
144                     $this->fixtures[] = $fixture;
145 
146                     // backwards compatibility: Load first fixture into $this->fixture
147                     if($i == 0) $this->fixture = $fixture;
148                     $i++;
149                 }
150             }
151             
152             $this->logInWithPermission("ADMIN");
153         }
154         
155         // Set up email
156         $this->originalMailer = Email::mailer();
157         $this->mailer = new TestMailer();
158         Email::set_mailer($this->mailer);
159         Email::send_all_emails_to(null);
160     }
161     
162     /**
163      * Called once per test case ({@link SapphireTest} subclass).
164      * This is different to {@link setUp()}, which gets called once
165      * per method. Useful to initialize expensive operations which
166      * don't change state for any called method inside the test,
167      * e.g. dynamically adding an extension. See {@link tearDownOnce()}
168      * for tearing down the state again.
169      */
170     function setUpOnce() {
171         // Remove any illegal extensions that are present
172         foreach($this->illegalExtensions as $class => $extensions) {
173             foreach($extensions as $extension) {
174                 if (Object::has_extension($class, $extension)) {
175                     if(!isset($this->extensionsToReapply[$class])) $this->extensionsToReapply[$class] = array();
176                     $this->extensionsToReapply[$class][] = $extension;
177                     Object::remove_extension($class, $extension);
178                     $isAltered = true;
179                 }
180             }
181         }
182 
183         // Add any required extensions that aren't present
184         foreach($this->requiredExtensions as $class => $extensions) {
185             $this->extensionsToRemove[$class] = array();
186             foreach($extensions as $extension) {
187                 if(!Object::has_extension($class, $extension)) {
188                     if(!isset($this->extensionsToRemove[$class])) $this->extensionsToReapply[$class] = array();
189                     $this->extensionsToRemove[$class][] = $extension;
190                     Object::add_extension($class, $extension);
191                     $isAltered = true;
192                 }
193             }
194         }
195         
196         // If we have made changes to the extensions present, then migrate the database schema.
197         if($this->extensionsToReapply || $this->extensionsToRemove || $this->extraDataObjects) {
198             if(!self::using_temp_db()) self::create_temp_db();
199             $this->resetDBSchema(true);
200         }
201         // clear singletons, they're caching old extension info 
202         // which is used in DatabaseAdmin->doBuild()
203         global $_SINGLETONS;
204         $_SINGLETONS = array();
205     }
206     
207     /**
208      * tearDown method that's called once per test class rather once per test method.
209      */
210     function tearDownOnce() {
211         // If we have made changes to the extensions present, then migrate the database schema.
212         if($this->extensionsToReapply || $this->extensionsToRemove) {
213             // Remove extensions added for testing
214             foreach($this->extensionsToRemove as $class => $extensions) {
215                 foreach($extensions as $extension) {
216                     Object::remove_extension($class, $extension);
217                 }
218             }
219 
220             // Reapply ones removed
221             foreach($this->extensionsToReapply as $class => $extensions) {
222                 foreach($extensions as $extension) {
223                     Object::add_extension($class, $extension);
224                 }
225             }
226         }
227         
228         if($this->extensionsToReapply || $this->extensionsToRemove || $this->extraDataObjects) {
229             $this->resetDBSchema();
230         }
231     }
232     
233     /**
234      * Array
235      */
236     protected $fixtureDictionary;
237     
238     
239     /**
240      * Get the ID of an object from the fixture.
241      * @param $className The data class, as specified in your fixture file.  Parent classes won't work
242      * @param $identifier The identifier string, as provided in your fixture file
243      * @return int
244      */
245     protected function idFromFixture($className, $identifier) {
246         if(!$this->fixtures) {
247             user_error("You've called idFromFixture() but you haven't specified static \$fixture_file.\n", E_USER_WARNING);
248             return;
249         }
250         
251         foreach($this->fixtures as $fixture) {
252             $match = $fixture->idFromFixture($className, $identifier);
253             if($match) return $match;
254         }
255         
256         $fixtureFiles = Object::get_static(get_class($this), 'fixture_file');
257         user_error(sprintf(
258             "Couldn't find object '%s' (class: %s) in files %s",
259             $identifier,
260             $className,
261             (is_array($fixtureFiles)) ? implode(',', $fixtureFiles) : $fixtureFiles
262         ), E_USER_ERROR);
263         
264         return false;
265     }
266     
267     /**
268      * Return all of the IDs in the fixture of a particular class name.
269      * Will collate all IDs form all fixtures if multiple fixtures are provided.
270      * 
271      * @param string $className
272      * @return A map of fixture-identifier => object-id
273      */
274     protected function allFixtureIDs($className) {
275         if(!$this->fixtures) {
276             user_error("You've called allFixtureIDs() but you haven't specified static \$fixture_file.\n", E_USER_WARNING);
277             return;
278         }
279         
280         $ids = array();
281         foreach($this->fixtures as $fixture) {
282             $ids += $fixture->allFixtureIDs($className);
283         }
284         
285         return $ids;
286     }
287 
288     /**
289      * Get an object from the fixture.
290      * @param $className The data class, as specified in your fixture file.  Parent classes won't work
291      * @param $identifier The identifier string, as provided in your fixture file
292      */
293     protected function objFromFixture($className, $identifier) {
294         if(!$this->fixtures) {
295             user_error("You've called objFromFixture() but you haven't specified static \$fixture_file.\n", E_USER_WARNING);
296             return;
297         }
298         
299         foreach($this->fixtures as $fixture) {
300             $match = $fixture->objFromFixture($className, $identifier);
301             if($match) return $match;
302         }
303 
304         $fixtureFiles = Object::get_static(get_class($this), 'fixture_file');
305         user_error(sprintf(
306             "Couldn't find object '%s' (class: %s) in files %s",
307             $identifier,
308             $className,
309             (is_array($fixtureFiles)) ? implode(',', $fixtureFiles) : $fixtureFiles
310         ), E_USER_ERROR);
311         
312         return false;
313     }
314     
315     /**
316      * Load a YAML fixture file into the database.
317      * Once loaded, you can use idFromFixture() and objFromFixture() to get items from the fixture.
318      * Doesn't clear existing fixtures.
319      *
320      * @param $fixtureFile The location of the .yml fixture file, relative to the site base dir
321      */
322     function loadFixture($fixtureFile) {
323         $parser = new Spyc();
324         $fixtureContent = $parser->load(Director::baseFolder().'/'.$fixtureFile);
325         
326         $fixture = new YamlFixture($fixtureFile);
327         $fixture->saveIntoDatabase();
328         $this->fixtures[] = $fixture;
329     }
330     
331     /**
332      * Clear all fixtures which were previously loaded through
333      * {@link loadFixture()}.
334      */
335     function clearFixtures() {
336         $this->fixtures = array();
337     }
338     
339     function tearDown() {
340         // Restore email configuration
341         Email::set_mailer($this->originalMailer);
342         $this->originalMailer = null;
343         $this->mailer = null;
344 
345         // Restore password validation
346         Member::set_password_validator($this->originalMemberPasswordValidator);
347         
348         // Restore requirements
349         Requirements::set_backend($this->originalRequirements);
350 
351         // Mark test as no longer being run - we use originalIsRunningTest to allow for nested SapphireTest calls
352         self::$is_running_test = $this->originalIsRunningTest;
353         $this->originalIsRunningTest = null;
354 
355         // Reset theme setting
356         SSViewer::set_theme($this->originalTheme);
357 
358         // Reset mocked datetime
359         SS_Datetime::clear_mock_now();
360         
361         // Restore nested_urls state
362         if ( $this->originalNestedURLsState )
363             SiteTree::enable_nested_urls();
364         else
365             SiteTree::disable_nested_urls();
366         
367         // Stop the redirection that might have been requested in the test.
368         // Note: Ideally a clean Controller should be created for each test. 
369         // Now all tests executed in a batch share the same controller.
370         $controller = Controller::curr();
371         if ( $controller && $controller->response && $controller->response->getHeader('Location') ) {
372             $controller->response->setStatusCode(200);
373             $controller->response->removeHeader('Location');
374         }
375     }
376     /**
377      * Clear the log of emails sent
378      */
379     function clearEmails() {
380         return $this->mailer->clearEmails();
381     }
382 
383     /**
384      * Search for an email that was sent.
385      * All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
386      * @param $to
387      * @param $from
388      * @param $subject
389      * @param $content
390      * @return An array containing the keys: 'type','to','from','subject','content', 'plainContent','attachedFiles','customHeaders','htmlContent',inlineImages'
391      */
392     function findEmail($to, $from = null, $subject = null, $content = null) {
393         return $this->mailer->findEmail($to, $from, $subject, $content);
394     }
395     
396     /**
397      * Assert that the matching email was sent since the last call to clearEmails()
398      * All of the parameters can either be a string, or, if they start with "/", a PREG-compatible regular expression.
399      * @param $to
400      * @param $from
401      * @param $subject
402      * @param $content
403      * @return An array containing the keys: 'type','to','from','subject','content', 'plainContent','attachedFiles','customHeaders','htmlContent',inlineImages'
404      */
405     function assertEmailSent($to, $from = null, $subject = null, $content = null) {
406         // To do - this needs to be turned into a "real" PHPUnit ass
407         if(!$this->findEmail($to, $from, $subject, $content)) {
408             
409             $infoParts = "";
410             $withParts = array();
411             if($to) $infoParts .= " to '$to'";
412             if($from) $infoParts .= " from '$from'";
413             if($subject) $withParts[] = "subject '$subject'";
414             if($content) $withParts[] = "content '$content'";
415             if($withParts) $infoParts .= " with " . implode(" and ", $withParts);
416             
417             throw new PHPUnit_Framework_AssertionFailedError(
418                 "Failed asserting that an email was sent$infoParts."
419             );
420         }
421     }
422 
423 
424     /**
425      * Assert that the given {@link DataObjectSet} includes DataObjects matching the given key-value
426      * pairs.  Each match must correspond to 1 distinct record.
427      * 
428      * @param $matches The patterns to match.  Each pattern is a map of key-value pairs.  You can
429      * either pass a single pattern or an array of patterns.
430      * @param $dataObjectSet The {@link DataObjectSet} to test.
431      *
432      * Examples
433      * --------
434      * Check that $members includes an entry with Email = sam@example.com:
435      *      $this->assertDOSContains(array('Email' => '...@example.com'), $members); 
436      * 
437      * Check that $members includes entries with Email = sam@example.com and with 
438      * Email = ingo@example.com:
439      *      $this->assertDOSContains(array( 
440      *         array('Email' => '...@example.com'), 
441      *         array('Email' => 'i...@example.com'), 
442      *      ), $members); 
443      */
444     function assertDOSContains($matches, $dataObjectSet) {
445         $extracted = array();
446         foreach($dataObjectSet as $item) $extracted[] = $item->toMap();
447         
448         foreach($matches as $match) {
449             $matched = false;
450             foreach($extracted as $i => $item) {
451                 if($this->dataObjectArrayMatch($item, $match)) {
452                     // Remove it from $extracted so that we don't get duplicate mapping.
453                     unset($extracted[$i]);
454                     $matched = true;
455                     break;
456                 }
457             }
458 
459             // We couldn't find a match - assertion failed
460             if(!$matched) {
461                 throw new PHPUnit_Framework_AssertionFailedError(
462                     "Failed asserting that the DataObjectSet contains an item matching "
463                         . var_export($match, true) . "\n\nIn the following DataObjectSet:\n" 
464                         . $this->DOSSummaryForMatch($dataObjectSet, $match)
465                 );
466             }
467 
468         }
469     } 
470     
471     /**
472      * Assert that the given {@link DataObjectSet} includes only DataObjects matching the given 
473      * key-value pairs.  Each match must correspond to 1 distinct record.
474      * 
475      * @param $matches The patterns to match.  Each pattern is a map of key-value pairs.  You can
476      * either pass a single pattern or an array of patterns.
477      * @param $dataObjectSet The {@link DataObjectSet} to test.
478      *
479      * Example
480      * --------
481      * Check that *only* the entries Sam Minnee and Ingo Schommer exist in $members.  Order doesn't 
482      * matter:
483      *     $this->assertDOSEquals(array( 
484      *        array('FirstName' =>'Sam', 'Surname' => 'Minnee'), 
485      *        array('FirstName' => 'Ingo', 'Surname' => 'Schommer'), 
486      *      ), $members); 
487      */
488     function assertDOSEquals($matches, $dataObjectSet) {
489         if(!$dataObjectSet) return false;
490         
491         $extracted = array();
492         foreach($dataObjectSet as $item) $extracted[] = $item->toMap();
493         
494         foreach($matches as $match) {
495             $matched = false;
496             foreach($extracted as $i => $item) {
497                 if($this->dataObjectArrayMatch($item, $match)) {
498                     // Remove it from $extracted so that we don't get duplicate mapping.
499                     unset($extracted[$i]);
500                     $matched = true;
501                     break;
502                 }
503             }
504 
505             // We couldn't find a match - assertion failed
506             if(!$matched) {
507                 throw new PHPUnit_Framework_AssertionFailedError(
508                     "Failed asserting that the DataObjectSet contains an item matching "
509                         . var_export($match, true) . "\n\nIn the following DataObjectSet:\n" 
510                         . $this->DOSSummaryForMatch($dataObjectSet, $match)
511                 );
512             }
513         }
514         
515         // If we have leftovers than the DOS has extra data that shouldn't be there
516         if($extracted) {
517             // If we didn't break by this point then we couldn't find a match
518             throw new PHPUnit_Framework_AssertionFailedError(
519                 "Failed asserting that the DataObjectSet contained only the given items, the "
520                     . "following items were left over:\n" . var_export($extracted, true)
521             );
522         }
523     } 
524 
525     /**
526      * Assert that the every record in the given {@link DataObjectSet} matches the given key-value
527      * pairs.
528      * 
529      * @param $match The pattern to match.  The pattern is a map of key-value pairs.
530      * @param $dataObjectSet The {@link DataObjectSet} to test.
531      *
532      * Example
533      * --------
534      * Check that every entry in $members has a Status of 'Active':
535      *     $this->assertDOSAllMatch(array('Status' => 'Active'), $members); 
536      */
537     function assertDOSAllMatch($match, $dataObjectSet) {
538         $extracted = array();
539         foreach($dataObjectSet as $item) $extracted[] = $item->toMap();
540 
541         foreach($extracted as $i => $item) {
542             if(!$this->dataObjectArrayMatch($item, $match)) {
543                 throw new PHPUnit_Framework_AssertionFailedError(
544                     "Failed asserting that the the following item matched " 
545                     . var_export($match, true) . ": " . var_export($item, true)
546                 );
547             }
548         }
549     } 
550     
551     /**
552      * Helper function for the DOS matchers
553      */
554     private function dataObjectArrayMatch($item, $match) {
555         foreach($match as $k => $v) {
556             if(!isset($item[$k]) || $item[$k] != $v) return false;
557         }
558         return true;
559     }
560 
561     /**
562      * Helper function for the DOS matchers
563      */
564     private function DOSSummaryForMatch($dataObjectSet, $match) {
565         $extracted = array();
566         foreach($dataObjectSet as $item) $extracted[] = array_intersect_key($item->toMap(), $match);
567         return var_export($extracted, true);
568     }
569 
570     /**
571      * Returns true if we are currently using a temporary database
572      */
573     static function using_temp_db() {
574         $dbConn = DB::getConn();
575         return $dbConn && (substr($dbConn->currentDatabase(),0,5) == 'tmpdb');
576     }
577     
578     /**
579      * @todo Make this db agnostic
580      */
581     static function kill_temp_db() {
582         // Delete our temporary database
583         if(self::using_temp_db()) {
584             $dbConn = DB::getConn();
585             $dbName = $dbConn->currentDatabase();
586             if($dbName && DB::getConn()->databaseExists($dbName)) {
587                 // Some DataObjectsDecorators keep a static cache of information that needs to 
588                 // be reset whenever the database is killed
589                 foreach(ClassInfo::subclassesFor('DataObjectDecorator') as $class) {
590                     $toCall = array($class, 'on_db_reset');
591                     if(is_callable($toCall)) call_user_func($toCall);
592                 }
593 
594                 // echo "Deleted temp database " . $dbConn->currentDatabase() . "\n";
595                 $dbConn->dropDatabase();
596             }
597         }
598     }
599     
600     /**
601      * Remove all content from the temporary database.
602      */
603     static function empty_temp_db() {
604         if(self::using_temp_db()) {
605             $dbadmin = new DatabaseAdmin();
606             $dbadmin->clearAllData();
607             
608             // Some DataObjectsDecorators keep a static cache of information that needs to 
609             // be reset whenever the database is cleaned out
610             foreach(array_merge(ClassInfo::subclassesFor('DataObjectDecorator'), ClassInfo::subclassesFor('DataObject')) as $class) {
611                 $toCall = array($class, 'on_db_reset');
612                 if(is_callable($toCall)) call_user_func($toCall);
613             }
614         }
615     }
616     
617     /**
618      * @todo Make this db agnostic
619      */
620     static function create_temp_db() {
621         // Create a temporary database
622         $dbConn = DB::getConn();
623         $dbname = 'tmpdb' . rand(1000000,9999999);
624         while(!$dbname || $dbConn->databaseExists($dbname)) {
625             $dbname = 'tmpdb' . rand(1000000,9999999);
626         }
627         
628         $dbConn->selectDatabase($dbname);
629         $dbConn->createDatabase();
630         
631         $st = new SapphireTest();
632         $st->resetDBSchema();
633         
634         return $dbname;
635     }
636     
637     static function delete_all_temp_dbs() {
638         foreach(DB::getConn()->allDatabaseNames() as $dbName) {
639             if(preg_match('/^tmpdb[0-9]+$/', $dbName)) {
640                 DB::getConn()->dropDatabaseByName($dbName);
641                 echo "<li>Dropped databse \"$dbName\"\n";
642                 flush();
643             }
644         }
645     }
646     
647     /**
648      * Reset the testing database's schema.
649      * @param $includeExtraDataObjects If true, the extraDataObjects tables will also be included
650      */
651     function resetDBSchema($includeExtraDataObjects = false) {
652         if(self::using_temp_db()) {
653             // clear singletons, they're caching old extension info which is used in DatabaseAdmin->doBuild()
654             global $_SINGLETONS;
655             $_SINGLETONS = array();
656 
657             $dataClasses = ClassInfo::subclassesFor('DataObject');
658             array_shift($dataClasses);
659 
660             $conn = DB::getConn();
661             $conn->beginSchemaUpdate();
662             DB::quiet();
663 
664             foreach($dataClasses as $dataClass) {
665                 // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness
666                 if(class_exists($dataClass)) {
667                     $SNG = singleton($dataClass);
668                     if(!($SNG instanceof TestOnly)) $SNG->requireTable();
669                 }
670             }
671 
672             // If we have additional dataobjects which need schema, do so here:
673             if($includeExtraDataObjects && $this->extraDataObjects) {
674                 foreach($this->extraDataObjects as $dataClass) {
675                     $SNG = singleton($dataClass);
676                     if(singleton($dataClass) instanceof DataObject) $SNG->requireTable();
677                 }
678             }
679 
680             $conn->endSchemaUpdate();
681 
682             ClassInfo::reset_db_cache();
683             singleton('DataObject')->flushCache();
684         }
685     }
686     
687     /**
688      * Create a member and group with the given permission code, and log in with it.
689      * Returns the member ID.
690      */
691     function logInWithPermission($permCode = "ADMIN") {
692         if(!isset($this->cache_generatedMembers[$permCode])) {
693             $group = new Group();
694             $group->Title = "$permCode group";
695             $group->write();
696 
697             $permission = new Permission();
698             $permission->Code = $permCode;
699             $permission->write();
700             $group->Permissions()->add($permission);
701             
702             $member = DataObject::get_one('Member', sprintf('"Email" = \'%s\'', "$permCode@example.org"));
703             if(!$member) $member = new Member();
704             
705             $member->FirstName = $permCode;
706             $member->Surname = "User";
707             $member->Email = "$permCode@example.org";
708             $member->write();
709             $group->Members()->add($member);
710             
711             $this->cache_generatedMembers[$permCode] = $member;
712         }
713         
714         $this->cache_generatedMembers[$permCode]->logIn();
715     }
716     
717     /**
718      * Cache for logInWithPermission()
719      */
720     protected $cache_generatedMembers = array();
721 }
722 
723 ?>
724 
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.2 API Docs API documentation generated by ApiGen 2.8.0