Completed
Push — master ( b6018a...af2f64 )
by Andreas
03:13
created

connection::invalidate_cache()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
c 0
b 0
f 0
nc 2
nop 0
dl 0
loc 7
rs 9.4285
ccs 0
cts 6
cp 0
crap 12
1
<?php
2
/**
3
 * @author CONTENT CONTROL http://www.contentcontrol-berlin.de/
4
 * @copyright CONTENT CONTROL http://www.contentcontrol-berlin.de/
5
 * @license http://www.gnu.org/licenses/gpl.html GNU General Public License
6
 */
7
8
namespace midgard\portable\storage;
9
10
use midgard\portable\driver;
11
use midgard\portable\classgenerator;
12
use midgard\portable\api\user;
13
use midgard\portable\api\config;
14
use midgard\portable\api\error\exception;
15
use midgard\portable\storage\type\datetime;
16
use Doctrine\ORM\EntityManager;
17
use Doctrine\DBAL\Types\Type;
18
use Doctrine\Common\Cache\ClearableCache;
19
use Monolog\Logger;
20
use Monolog\Handler\StreamHandler;
21
use midgard_connection;
22
23
class connection
24
{
25
    /**
26
     * @var Logger
27
     */
28
    private static $logger;
29
30
    /**
31
     * Loglevel translation table.
32
     *
33
     * The semantics of info and notice/message are unfortunately reversed between Monolog
34
     * and Midgard, so it looks a bit confusing..
35
     *
36
     * @var array
37
     */
38
    private static $loglevels = array(
39
        'error' => Logger::ERROR,
40
        'warn' => Logger::WARNING,
41
        'warning' => Logger::WARNING,
42
        'info' => Logger::NOTICE,
43
        'message' => Logger::INFO,
44
        'debug' => Logger::DEBUG
45
    );
46
47
    /**
48
     * Flag for automatically starting up during initialize
49
     *
50
     * @var boolean
51
     */
52
    private static $autostart = true;
53
54
    /**
55
     * Initialization parameters
56
     *
57
     * @param array
58
     */
59
    private static $parameters = array();
60
61
    private $user;
62
63
    /**
64
     * @var \Doctrine\ORM\EntityManager
65
     */
66
    protected $em;
67
68
    /**
69
     * @var \midgard\portable\storage\connection
70
     */
71
    protected static $instance;
72
73 10
    public function __construct(EntityManager $em)
0 ignored issues
show
Bug introduced by
You have injected the EntityManager via parameter $em. This is generally not recommended as it might get closed and become unusable. Instead, it is recommended to inject the ManagerRegistry and retrieve the EntityManager via getManager() each time you need it.

The EntityManager might become unusable for example if a transaction is rolled back and it gets closed. Let’s assume that somewhere in your application, or in a third-party library, there is code such as the following:

function someFunction(ManagerRegistry $registry) {
    $em = $registry->getManager();
    $em->getConnection()->beginTransaction();
    try {
        // Do something.
        $em->getConnection()->commit();
    } catch (\Exception $ex) {
        $em->getConnection()->rollback();
        $em->close();

        throw $ex;
    }
}

If that code throws an exception and the EntityManager is closed. Any other code which depends on the same instance of the EntityManager during this request will fail.

On the other hand, if you instead inject the ManagerRegistry, the getManager() method guarantees that you will always get a usable manager instance.

Loading history...
74
    {
75 10
        $this->em = $em;
76 10
    }
77
78
    /**
79
     * @return \Doctrine\ORM\EntityManager
80
     */
81 164
    public static function get_em()
82
    {
83 164
        if (self::$instance === null) {
84
            throw new \Exception('Not initialized');
85
        }
86 164
        return self::$instance->em;
87
    }
88
89 99
    public static function get_user()
90
    {
91 99
        return self::$instance->user;
92
    }
93
94 8
    public static function set_user(user $user = null)
95
    {
96 8
        if (self::$instance === null) {
97
            throw new \Exception('Not initialized');
98
        }
99 8
        self::$instance->user = $user;
100 8
    }
101
102
    /**
103
     * Generate a new GUID
104
     *
105
     * @return string The generated GUID
106
     */
107 115
    public static function generate_guid()
108
    {
109 115
        $sql = 'SELECT ' . self::get_em()->getConnection()->getDatabasePlatform()->getGuidExpression();
110 115
        return md5(self::get_em()->getConnection()->query($sql)->fetchColumn(0));
111
    }
112
113
    /**
114
     * Invalidate ClassMetadata cache
115
     */
116
    public static function invalidate_cache()
117
    {
118
        $cache = self::get_em()->getConfiguration()->getMetadataCacheImpl();
119
        if ($cache && $cache instanceof ClearableCache) {
120
            $cache->deleteAll();
121
        }
122
    }
123
124
    /**
125
     * Toggle autostart
126
     */
127
    public static function set_autostart($autostart)
128
    {
129
        self::$autostart = $autostart;
130
    }
131
132
    /**
133
     * Initialize Midgard connection
134
     */
135 10
    public static function initialize(driver $driver, array $db_config, $dev_mode = false)
136
    {
137 10
        if (extension_loaded('midgard') || extension_loaded('midgard2')) {
138
            throw new \RuntimeException('midgard-portable cannot run while a Midgard extension is loaded');
139
        }
140 10
        $vardir = $driver->get_vardir();
141
142 10
        $mgd_config = new config;
143 10
        $mgd_config->vardir = $vardir;
144 10
        $mgd_config->cachedir = $vardir . '/cache';
145 10
        $mgd_config->blobdir = $vardir . '/blobs';
146 10
        $mgd_config->sharedir = $vardir . '/schemas';
147 10
        $mgd_config->logfilename = $vardir . '/log/midgard-portable.log';
148
        // TODO: Set rest of config values from $config and $driver
149
150
        // we open the config before startup to have logfile available
151 10
        midgard_connection::get_instance()->open_config($mgd_config);
152
153 10
        self::$parameters = array('driver' => $driver, 'db_config' => $db_config, 'dev_mode' => $dev_mode);
154 10
        if (self::$autostart) {
155 10
            static::startup();
156 10
        }
157 10
    }
158
159
    public static function get_parameter($name)
160
    {
161
        if (!array_key_exists($name, self::$parameters)) {
162
            throw new \RuntimeException('Parameter "' . $name . '" is not available');
163
        }
164
        return self::$parameters[$name];
165
    }
166
167
    /**
168
     * Start the API emulation layer
169
     */
170 10
    public static function startup()
171
    {
172 10
        if (empty(self::$parameters)) {
173
            throw new \RuntimeError('Not initialized');
174
        }
175 10
        $driver = self::$parameters['driver'];
176 10
        $db_config = self::$parameters['db_config'];
177 10
        $dev_mode = self::$parameters['dev_mode'];
178 10
        $vardir = $driver->get_vardir();
179
        // generate and include entities file if its a fresh namespace
180
        // otherwise it should be included already
181 10
        if ($driver->is_fresh_namespace()) {
182 10
            $entityfile = $vardir . '/mgdschema_classes.php';
183 10
            if ($dev_mode || !file_exists($entityfile)) {
184 10
                $classgenerator = new classgenerator($driver->get_manager(), $entityfile, $dev_mode);
185 10
                $classgenerator->write($driver->get_namespace());
186 10
            }
187 10
            require $entityfile;
188 10
        }
189
190 10
        $config = \Doctrine\ORM\Tools\Setup::createConfiguration($dev_mode, $vardir . '/cache');
191 10
        $config->addFilter('softdelete', 'midgard\\portable\\storage\\filter\\softdelete');
192 10
        $config->setMetadataDriverImpl($driver);
193 10
        $config->addEntityNamespace('midgard', $driver->get_namespace());
194 10
        $config->setClassMetadataFactoryName('\\midgard\\portable\\mapping\\factory');
195
196 10
        if (!array_key_exists('charset', $db_config)) {
197 10
            $db_config['charset'] = 'utf8';
198 10
        }
199
200 10
        $em = \Doctrine\ORM\EntityManager::create($db_config, $config);
201 10
        $em->getFilters()->enable('softdelete');
202 10
        $em->getEventManager()->addEventSubscriber(new subscriber);
203
204 10
        if (!Type::hasType(datetime::TYPE)) {
205
            Type::addType(datetime::TYPE, 'midgard\portable\storage\type\datetime');
206
        }
207
208 10
        $midgard = midgard_connection::get_instance();
209 10
        $level = self::$loglevels[$midgard->get_loglevel()];
210 10
        if ($level === Logger::DEBUG) {
211
            $logger = new Logger('doctrine');
212
            $logger->pushHandler(new StreamHandler($midgard->config->logfilename, $level));
213
214
            $em->getConnection()->getConfiguration()->setSQLLogger(new sqllogger($logger));
215
        }
216
217 10
        self::$instance = new static($em);
218 10
    }
219
220
    /**
221
     * Get Logger instance
222
     *
223
     * @return Logger
224
     */
225 4
    public static function log()
226
    {
227 4
        if (self::$logger === null) {
228 1
            $midgard = midgard_connection::get_instance();
229 1
            if ($midgard->config->logfilename) {
230 1
                $logdir = dirname($midgard->config->logfilename);
231 1
                if (   !is_dir($logdir)
232 1
                    && !mkdir($logdir, 0777, true)) {
233
                    throw exception::user_data('Log directory could not be created');
234
                }
235 1
                self::$logger = new Logger('midgard-portable');
236 1
                self::$logger->pushHandler(new StreamHandler($midgard->config->logfilename, self::$loglevels[$midgard->get_loglevel()]));
237 1
            } else {
238
                throw exception::user_data('log filename not set in config');
239
            }
240 1
        }
241 4
        return self::$logger;
242
    }
243
}
244