OrmFunctionalTestCase.php 10.9 KB
Newer Older
romanb's avatar
romanb committed
1
<?php
romanb's avatar
romanb committed
2

3
namespace Doctrine\Tests;
romanb's avatar
romanb committed
4

romanb's avatar
romanb committed
5
/**
6
 * Base testcase class for all functional ORM testcases.
romanb's avatar
romanb committed
7
 *
8
 * @since 2.0
romanb's avatar
romanb committed
9
 */
10
abstract class OrmFunctionalTestCase extends OrmTestCase
romanb's avatar
romanb committed
11
{
12 13
    /* The metadata cache shared between all functional tests. */
    private static $_metadataCacheImpl = null;
14 15
    /* The query cache shared between all functional tests. */
    private static $_queryCacheImpl = null;
16

17 18 19
    /* Shared connection when a TestCase is run alone (outside of it's functional suite) */
    private static $_sharedConn;
    
20 21 22
    /**
     * @var \Doctrine\ORM\EntityManager
     */
23 24
    protected $_em;

25 26 27
    /**
     * @var \Doctrine\ORM\Tools\SchemaTool
     */
28
    protected $_schemaTool;
29

30 31 32 33 34
    /**
     * @var \Doctrine\DBAL\Logging\DebugStack
     */
    protected $_sqlLoggerStack;

35 36 37 38 39 40 41 42 43 44 45 46
    /** The names of the model sets used in this testcase. */
    private $_usedModelSets = array();

    /** Whether the database schema has already been created. */
    private static $_tablesCreated = array();

    /** List of model sets and their classes. */
    private static $_modelSets = array(
        'cms' => array(
            'Doctrine\Tests\Models\CMS\CmsUser',
            'Doctrine\Tests\Models\CMS\CmsPhonenumber',
            'Doctrine\Tests\Models\CMS\CmsAddress',
47 48
            'Doctrine\Tests\Models\CMS\CmsGroup',
            'Doctrine\Tests\Models\CMS\CmsArticle'
49 50
        ),
        'forum' => array(),
51 52 53
        'company' => array(
            'Doctrine\Tests\Models\Company\CompanyPerson',
            'Doctrine\Tests\Models\Company\CompanyEmployee',
romanb's avatar
romanb committed
54 55 56 57
            'Doctrine\Tests\Models\Company\CompanyManager',
            'Doctrine\Tests\Models\Company\CompanyOrganization',
            'Doctrine\Tests\Models\Company\CompanyEvent',
            'Doctrine\Tests\Models\Company\CompanyAuction',
58 59
            'Doctrine\Tests\Models\Company\CompanyRaffle',
            'Doctrine\Tests\Models\Company\CompanyCar'
60
        ),
piccoloprincipe's avatar
piccoloprincipe committed
61 62
        'ecommerce' => array(
            'Doctrine\Tests\Models\ECommerce\ECommerceCart',
63 64
            'Doctrine\Tests\Models\ECommerce\ECommerceCustomer',
            'Doctrine\Tests\Models\ECommerce\ECommerceProduct',
65
            'Doctrine\Tests\Models\ECommerce\ECommerceShipping',
66 67
            'Doctrine\Tests\Models\ECommerce\ECommerceFeature',
            'Doctrine\Tests\Models\ECommerce\ECommerceCategory'
piccoloprincipe's avatar
piccoloprincipe committed
68
        ),
69
        'generic' => array(
70 71 72 73
            'Doctrine\Tests\Models\Generic\BooleanModel',
            'Doctrine\Tests\Models\Generic\DateTimeModel',
            'Doctrine\Tests\Models\Generic\DecimalModel',
            'Doctrine\Tests\Models\Generic\SerializationModel',
74 75 76 77 78
        ),
        'routing' => array(
            'Doctrine\Tests\Models\Routing\RoutingLeg',
            'Doctrine\Tests\Models\Routing\RoutingLocation',
            'Doctrine\Tests\Models\Routing\RoutingRoute',
79
            'Doctrine\Tests\Models\Routing\RoutingRouteBooking',
80
        ),
81 82 83 84 85 86
        'navigation' => array(
            'Doctrine\Tests\Models\Navigation\NavCountry',
            'Doctrine\Tests\Models\Navigation\NavPhotos',
            'Doctrine\Tests\Models\Navigation\NavTour',
            'Doctrine\Tests\Models\Navigation\NavPointOfInterest',
        ),
87 88 89
    );

    protected function useModelSet($setName)
romanb's avatar
romanb committed
90
    {
91
        $this->_usedModelSets[$setName] = true;
romanb's avatar
romanb committed
92 93 94
    }
    
    /**
95
     * Sweeps the database tables and clears the EntityManager.
romanb's avatar
romanb committed
96 97 98
     */
    protected function tearDown()
    {
99
        $conn = $this->sharedFixture['conn'];
100 101

        $this->_sqlLoggerStack->enabled = false;
102
        
103
        if (isset($this->_usedModelSets['cms'])) {
104 105 106 107 108 109
            $conn->executeUpdate('DELETE FROM cms_users_groups');
            $conn->executeUpdate('DELETE FROM cms_groups');
            $conn->executeUpdate('DELETE FROM cms_addresses');
            $conn->executeUpdate('DELETE FROM cms_phonenumbers');
            $conn->executeUpdate('DELETE FROM cms_articles');
            $conn->executeUpdate('DELETE FROM cms_users');
romanb's avatar
romanb committed
110
        }
111
        
piccoloprincipe's avatar
piccoloprincipe committed
112
        if (isset($this->_usedModelSets['ecommerce'])) {
113 114 115 116 117 118 119 120
            $conn->executeUpdate('DELETE FROM ecommerce_carts_products');
            $conn->executeUpdate('DELETE FROM ecommerce_products_categories');
            $conn->executeUpdate('DELETE FROM ecommerce_products_related');
            $conn->executeUpdate('DELETE FROM ecommerce_carts');
            $conn->executeUpdate('DELETE FROM ecommerce_customers');
            $conn->executeUpdate('DELETE FROM ecommerce_features');
            $conn->executeUpdate('DELETE FROM ecommerce_products');
            $conn->executeUpdate('DELETE FROM ecommerce_shippings');
121
            $conn->executeUpdate('UPDATE ecommerce_categories SET parent_id = NULL');
122
            $conn->executeUpdate('DELETE FROM ecommerce_categories');
piccoloprincipe's avatar
piccoloprincipe committed
123
        }
124
        
125
        if (isset($this->_usedModelSets['company'])) {
126 127 128
            $conn->executeUpdate('DELETE FROM company_persons_friends');
            $conn->executeUpdate('DELETE FROM company_managers');
            $conn->executeUpdate('DELETE FROM company_employees');
129
            $conn->executeUpdate('UPDATE company_persons SET spouse_id = NULL');
130 131 132
            $conn->executeUpdate('DELETE FROM company_persons');
            $conn->executeUpdate('DELETE FROM company_raffles');
            $conn->executeUpdate('DELETE FROM company_auctions');
133
            $conn->executeUpdate('UPDATE company_organizations SET main_event_id = NULL');
134 135
            $conn->executeUpdate('DELETE FROM company_events');
            $conn->executeUpdate('DELETE FROM company_organizations');
136
        }
137
        
138
        if (isset($this->_usedModelSets['generic'])) {
139
            $conn->executeUpdate('DELETE FROM boolean_model');
140
            $conn->executeUpdate('DELETE FROM date_time_model');
141 142
            $conn->executeUpdate('DELETE FROM decimal_model');
            $conn->executeUpdate('DELETE FROM serialize_model');
143
        }
144

145 146 147 148 149 150 151 152
        if (isset($this->_usedModelSets['routing'])) {
            $conn->executeUpdate('DELETE FROM RoutingRouteLegs');
            $conn->executeUpdate('DELETE FROM RoutingRouteBooking');
            $conn->executeUpdate('DELETE FROM RoutingRoute');
            $conn->executeUpdate('DELETE FROM RoutingLeg');
            $conn->executeUpdate('DELETE FROM RoutingLocation');
        }

153 154 155 156 157 158 159 160
        if(isset($this->_usedModelSets['navigation'])) {
            $conn->executeUpdate('DELETE FROM navigation_tour_pois');
            $conn->executeUpdate('DELETE FROM navigation_photos');
            $conn->executeUpdate('DELETE FROM navigation_pois');
            $conn->executeUpdate('DELETE FROM navigation_tours');
            $conn->executeUpdate('DELETE FROM navigation_countries');
        }

161
        $this->_em->clear();
romanb's avatar
romanb committed
162
    }
163

164 165 166 167
    /**
     * Creates a connection to the test database, if there is none yet, and
     * creates the necessary tables.
     */
168 169
    protected function setUp()
    {
170
        $forceCreateTables = false;
171
        
172
        if ( ! isset($this->sharedFixture['conn'])) {
173 174 175
            if ( ! isset(self::$_sharedConn)) {
                self::$_sharedConn = TestUtil::getConnection();
            }
176
            
177
            $this->sharedFixture['conn'] = self::$_sharedConn;
178
            
179 180 181
            if ($this->sharedFixture['conn']->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
                $forceCreateTables = true;
            }
182
        }
183
        
184 185
        if ( ! $this->_em) {
            $this->_em = $this->_getEntityManager();
186 187 188 189
            $this->_schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->_em);
        }

        $classes = array();
190
        
191
        foreach ($this->_usedModelSets as $setName => $bool) {
romanb's avatar
romanb committed
192
            if ( ! isset(self::$_tablesCreated[$setName])/* || $forceCreateTables*/) {
193 194 195
                foreach (self::$_modelSets[$setName] as $className) {
                    $classes[] = $this->_em->getClassMetadata($className);
                }
196
                
197 198 199
                self::$_tablesCreated[$setName] = true;
            }
        }
200
        
201
        if ($classes) {
romanb's avatar
romanb committed
202
            $this->_schemaTool->createSchema($classes);
203
        }
204 205

        $this->_sqlLoggerStack->enabled = true;
206 207
    }

208 209 210 211 212 213 214
    /**
     * Gets an EntityManager for testing purposes.
     *
     * @param Configuration $config The Configuration to pass to the EntityManager.
     * @param EventManager $eventManager The EventManager to pass to the EntityManager.
     * @return EntityManager
     */
215
    protected function _getEntityManager($config = null, $eventManager = null) {
216 217 218 219
        // NOTE: Functional tests use their own shared metadata cache, because
        // the actual database platform used during execution has effect on some
        // metadata mapping behaviors (like the choice of the ID generation).
        if (is_null(self::$_metadataCacheImpl)) {
220
            self::$_metadataCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
221
        }
222

223
        if (is_null(self::$_queryCacheImpl)) {
224
        	self::$_queryCacheImpl = new \Doctrine\Common\Cache\ArrayCache;
225
        }
226 227 228

        $this->_sqlLoggerStack = new \Doctrine\DBAL\Logging\DebugStack();
        $this->_sqlLoggerStack->enabled = false;
229
        
romanb's avatar
romanb committed
230 231
        //FIXME: two different configs! $conn and the created entity manager have
        // different configs.
232
        $config = new \Doctrine\ORM\Configuration();
233
        $config->setMetadataCacheImpl(self::$_metadataCacheImpl);
234
        $config->setQueryCacheImpl(self::$_queryCacheImpl);
235 236
        $config->setProxyDir(__DIR__ . '/Proxies');
        $config->setProxyNamespace('Doctrine\Tests\Proxies');
237
        
238
        $conn = $this->sharedFixture['conn'];
239
        $conn->getConfiguration()->setSQLLogger($this->_sqlLoggerStack);
240
        
241
        return \Doctrine\ORM\EntityManager::create($conn, $config);
242
    }
243 244 245

    protected function onNotSuccessfulTest(\Exception $e)
    {
246
        if ($e instanceof \PHPUnit_Framework_AssertionFailedError) {
247 248 249
            throw $e;
        }

250
        if(isset($this->_sqlLoggerStack->queries) && count($this->_sqlLoggerStack->queries)) {
251
            $queries = "";
252
            for($i = count($this->_sqlLoggerStack->queries)-1; $i > max(count($this->_sqlLoggerStack->queries)-25, 0); $i--) {
253
                $query = $this->_sqlLoggerStack->queries[$i];
254
                $params = array_map(function($p) { return "'".$p."'"; }, $query['params'] ?: array());
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
                $queries .= ($i+1).". SQL: '".$query['sql']."' Params: ".implode(", ", $params).PHP_EOL;
            }
            
            $trace = $e->getTrace();
            $traceMsg = "";
            foreach($trace AS $part) {
                if(isset($part['file'])) {
                    if(strpos($part['file'], "PHPUnit/") !== false) {
                        // Beginning with PHPUnit files we don't print the trace anymore.
                        break;
                    }

                    $traceMsg .= $part['file'].":".$part['line'].PHP_EOL;
                }
            }

            $message = "[".get_class($e)."] ".$e->getMessage().PHP_EOL.PHP_EOL."With queries:".PHP_EOL.$queries.PHP_EOL."Trace:".PHP_EOL.$traceMsg;

            throw new \Exception($message, (int)$e->getCode(), $e);
        }
        throw $e;
    }
piccoloprincipe's avatar
piccoloprincipe committed
277
}