|
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 = [ |
|
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 = []; |
|
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) |
|
|
|
|
|
|
74
|
|
|
{ |
|
75
|
10 |
|
$this->em = $em; |
|
76
|
10 |
|
} |
|
77
|
|
|
|
|
78
|
|
|
/** |
|
79
|
|
|
* @return \Doctrine\ORM\EntityManager |
|
80
|
|
|
*/ |
|
81
|
165 |
|
public static function get_em() |
|
82
|
|
|
{ |
|
83
|
165 |
|
if (self::$instance === null) { |
|
84
|
|
|
throw new \Exception('Not initialized'); |
|
85
|
|
|
} |
|
86
|
165 |
|
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 |
|
$vardir = $driver->get_vardir(); |
|
138
|
|
|
|
|
139
|
10 |
|
$mgd_config = new config; |
|
140
|
10 |
|
$mgd_config->vardir = $vardir; |
|
141
|
10 |
|
$mgd_config->cachedir = $vardir . '/cache'; |
|
142
|
10 |
|
$mgd_config->blobdir = $vardir . '/blobs'; |
|
143
|
10 |
|
$mgd_config->sharedir = $vardir . '/schemas'; |
|
144
|
10 |
|
$mgd_config->logfilename = $vardir . '/log/midgard-portable.log'; |
|
145
|
|
|
// TODO: Set rest of config values from $config and $driver |
|
146
|
|
|
|
|
147
|
|
|
// we open the config before startup to have logfile available |
|
148
|
10 |
|
midgard_connection::get_instance()->open_config($mgd_config); |
|
149
|
|
|
|
|
150
|
10 |
|
self::$parameters = ['driver' => $driver, 'db_config' => $db_config, 'dev_mode' => $dev_mode]; |
|
151
|
10 |
|
if (self::$autostart) { |
|
152
|
10 |
|
static::startup(); |
|
153
|
10 |
|
} |
|
154
|
10 |
|
} |
|
155
|
|
|
|
|
156
|
|
|
public static function get_parameter($name) |
|
157
|
|
|
{ |
|
158
|
|
|
if (!array_key_exists($name, self::$parameters)) { |
|
159
|
|
|
throw new \RuntimeException('Parameter "' . $name . '" is not available'); |
|
160
|
|
|
} |
|
161
|
|
|
return self::$parameters[$name]; |
|
162
|
|
|
} |
|
163
|
|
|
|
|
164
|
|
|
/** |
|
165
|
|
|
* Start the API emulation layer |
|
166
|
|
|
*/ |
|
167
|
10 |
|
public static function startup() |
|
168
|
|
|
{ |
|
169
|
10 |
|
if (empty(self::$parameters)) { |
|
170
|
|
|
throw new \RuntimeError('Not initialized'); |
|
171
|
|
|
} |
|
172
|
10 |
|
$driver = self::$parameters['driver']; |
|
173
|
10 |
|
$db_config = self::$parameters['db_config']; |
|
174
|
10 |
|
$dev_mode = self::$parameters['dev_mode']; |
|
175
|
10 |
|
$vardir = $driver->get_vardir(); |
|
176
|
|
|
// generate and include entities file if its a fresh namespace |
|
177
|
|
|
// otherwise it should be included already |
|
178
|
10 |
|
if ($driver->is_fresh_namespace()) { |
|
179
|
10 |
|
$entityfile = $vardir . '/mgdschema_classes.php'; |
|
180
|
10 |
|
if ($dev_mode || !file_exists($entityfile)) { |
|
181
|
10 |
|
$classgenerator = new classgenerator($driver->get_manager(), $entityfile, $dev_mode); |
|
182
|
10 |
|
$classgenerator->write($driver->get_namespace()); |
|
183
|
10 |
|
} |
|
184
|
10 |
|
require $entityfile; |
|
185
|
10 |
|
} |
|
186
|
|
|
|
|
187
|
10 |
|
$config = \Doctrine\ORM\Tools\Setup::createConfiguration($dev_mode, $vardir . '/cache'); |
|
188
|
10 |
|
$config->addFilter('softdelete', 'midgard\\portable\\storage\\filter\\softdelete'); |
|
189
|
10 |
|
$config->setMetadataDriverImpl($driver); |
|
190
|
10 |
|
$config->addEntityNamespace('midgard', $driver->get_namespace()); |
|
191
|
10 |
|
$config->setClassMetadataFactoryName('\\midgard\\portable\\mapping\\factory'); |
|
192
|
|
|
|
|
193
|
10 |
|
if (!array_key_exists('charset', $db_config)) { |
|
194
|
10 |
|
$db_config['charset'] = 'utf8'; |
|
195
|
10 |
|
} |
|
196
|
|
|
|
|
197
|
10 |
|
$em = \Doctrine\ORM\EntityManager::create($db_config, $config); |
|
198
|
10 |
|
$em->getFilters()->enable('softdelete'); |
|
199
|
10 |
|
$em->getEventManager()->addEventSubscriber(new subscriber); |
|
200
|
|
|
|
|
201
|
10 |
|
if (!Type::hasType(datetime::TYPE)) { |
|
202
|
|
|
Type::addType(datetime::TYPE, 'midgard\portable\storage\type\datetime'); |
|
203
|
|
|
} |
|
204
|
|
|
|
|
205
|
10 |
|
$midgard = midgard_connection::get_instance(); |
|
206
|
10 |
|
$level = self::$loglevels[$midgard->get_loglevel()]; |
|
207
|
10 |
|
if ($level === Logger::DEBUG) { |
|
208
|
|
|
$logger = new Logger('doctrine'); |
|
209
|
|
|
$logger->pushHandler(new StreamHandler($midgard->config->logfilename, $level)); |
|
210
|
|
|
|
|
211
|
|
|
$em->getConnection()->getConfiguration()->setSQLLogger(new sqllogger($logger)); |
|
212
|
|
|
} |
|
213
|
|
|
|
|
214
|
10 |
|
self::$instance = new static($em); |
|
215
|
10 |
|
} |
|
216
|
|
|
|
|
217
|
|
|
/** |
|
218
|
|
|
* Get Logger instance |
|
219
|
|
|
* |
|
220
|
|
|
* @return Logger |
|
221
|
|
|
*/ |
|
222
|
3 |
|
public static function log() |
|
223
|
|
|
{ |
|
224
|
3 |
|
if (self::$logger === null) { |
|
225
|
1 |
|
$midgard = midgard_connection::get_instance(); |
|
226
|
1 |
|
if ($midgard->config->logfilename) { |
|
227
|
1 |
|
$logdir = dirname($midgard->config->logfilename); |
|
228
|
1 |
|
if ( !is_dir($logdir) |
|
229
|
1 |
|
&& !mkdir($logdir, 0777, true)) { |
|
230
|
|
|
throw exception::user_data('Log directory could not be created'); |
|
231
|
|
|
} |
|
232
|
1 |
|
self::$logger = new Logger('midgard-portable'); |
|
233
|
1 |
|
self::$logger->pushHandler(new StreamHandler($midgard->config->logfilename, self::$loglevels[$midgard->get_loglevel()])); |
|
234
|
1 |
|
} else { |
|
235
|
|
|
throw exception::user_data('log filename not set in config'); |
|
236
|
|
|
} |
|
237
|
1 |
|
} |
|
238
|
3 |
|
return self::$logger; |
|
239
|
|
|
} |
|
240
|
|
|
} |
|
241
|
|
|
|
The
EntityManagermight 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:If that code throws an exception and the
EntityManageris closed. Any other code which depends on the same instance of theEntityManagerduring this request will fail.On the other hand, if you instead inject the
ManagerRegistry, thegetManager()method guarantees that you will always get a usable manager instance.