Passed
Branch master (4b377c)
by Andreas
03:22
created

connection::get_em()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 2.0625

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 3
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 6
ccs 3
cts 4
cp 0.75
crap 2.0625
rs 10
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 Monolog\Logger;
19
use Monolog\Handler\StreamHandler;
20
use midgard_connection;
21
use midgard\portable\storage\filter\softdelete;
22
use midgard\portable\mapping\factory;
23
use Doctrine\DBAL\Types\Types;
24
use Doctrine\ORM\ORMSetup;
25
26
class connection
27
{
28
    /**
29
     * @var Logger
30
     */
31
    private static $logger;
32
33
    /**
34
     * Loglevel translation table.
35
     *
36
     * The semantics of info and notice/message are unfortunately reversed between Monolog
37
     * and Midgard, so it looks a bit confusing..
38
     *
39
     * @var array
40
     */
41
    private static $loglevels = [
42
        'error' => Logger::ERROR,
43
        'warn' => Logger::WARNING,
44
        'warning' => Logger::WARNING,
45
        'info' => Logger::NOTICE,
46
        'message' => Logger::INFO,
47
        'debug' => Logger::DEBUG
48
    ];
49
50
    /**
51
     * Flag for automatically starting up during initialize
52
     *
53
     * @var boolean
54
     */
55
    private static $autostart = true;
56
57
    /**
58
     * Initialization parameters
59
     *
60
     * @param array
61
     */
62
    private static $parameters = [];
63
64
    private $user;
65
66
    private $namespace;
67
68
    /**
69
     * @var \Doctrine\ORM\EntityManager
70
     */
71
    protected $em;
72
73
    /**
74
     * @var \midgard\portable\storage\connection
75
     */
76
    protected static $instance;
77
78 9
    public function __construct(EntityManager $em, string $namespace)
79
    {
80 9
        $this->em = $em;
81 9
        $this->namespace = $namespace;
82
    }
83
84 166
    public static function get_em() : EntityManager
85
    {
86 166
        if (self::$instance === null) {
87
            throw new \Exception('Not initialized');
88
        }
89 166
        return self::$instance->em;
90
    }
91
92 100
    public static function get_user() : ?user
93
    {
94 100
        return self::$instance->user;
95
    }
96
97 8
    public static function set_user(user $user = null)
98
    {
99 8
        if (self::$instance === null) {
100
            throw new \Exception('Not initialized');
101
        }
102 8
        self::$instance->user = $user;
103
    }
104
105 170
    public static function get_fqcn(string $classname) : string
106
    {
107 170
        if (self::$instance->namespace) {
108 170
            return self::$instance->namespace . '\\' . $classname;
109
        }
110
        return $classname;
111
    }
112
113
    /**
114
     * Generate a new GUID
115
     */
116 116
    public static function generate_guid() : string
117
    {
118 116
        return bin2hex(random_bytes(16));
119
    }
120
121
    /**
122
     * Invalidate ClassMetadata cache
123
     */
124
    public static function invalidate_cache()
125
    {
126
        if ($cache = self::get_em()->getConfiguration()->getMetadataCache()) {
127
            $cache->clear();
128
        }
129
    }
130
131
    /**
132
     * Toggle autostart
133
     */
134
    public static function set_autostart(bool $autostart)
135
    {
136
        self::$autostart = $autostart;
137
    }
138
139
    /**
140
     * Initialize Midgard connection
141
     */
142 9
    public static function initialize(driver $driver, array $db_config, bool $dev_mode = false)
143
    {
144 9
        $vardir = $driver->get_vardir();
145
146 9
        $mgd_config = new config;
147 9
        $mgd_config->vardir = $vardir;
148 9
        $mgd_config->cachedir = $vardir . '/cache';
149 9
        $mgd_config->blobdir = $vardir . '/blobs';
150 9
        $mgd_config->sharedir = $vardir . '/schemas';
151 9
        $mgd_config->logfilename = $vardir . '/log/midgard-portable.log';
152
        // TODO: Set rest of config values from $config and $driver
153
154
        // we open the config before startup to have logfile available
155 9
        midgard_connection::get_instance()->open_config($mgd_config);
156
157 9
        self::$parameters = ['driver' => $driver, 'db_config' => $db_config, 'dev_mode' => $dev_mode];
158 9
        if (self::$autostart) {
159 9
            static::startup();
160
        }
161
    }
162
163
    public static function get_parameter(string $name)
164
    {
165
        if (!array_key_exists($name, self::$parameters)) {
166
            throw new \RuntimeException('Parameter "' . $name . '" is not available');
167
        }
168
        return self::$parameters[$name];
169
    }
170
171
    /**
172
     * Start the API emulation layer
173
     */
174 9
    public static function startup()
175
    {
176 9
        if (empty(self::$parameters)) {
177
            throw new \RuntimeException('Not initialized');
178
        }
179 9
        $driver = self::$parameters['driver'];
180 9
        $db_config = self::$parameters['db_config'];
181 9
        $dev_mode = self::$parameters['dev_mode'];
182 9
        $vardir = $driver->get_vardir();
183
        // generate and include entities file if its a fresh namespace
184
        // otherwise it should be included already
185 9
        if ($driver->is_fresh_namespace()) {
186 9
            $entityfile = $vardir . '/mgdschema_classes.php';
187 9
            if ($dev_mode || !file_exists($entityfile)) {
188 9
                $classgenerator = new classgenerator($driver->get_manager(), $entityfile, $dev_mode);
189 9
                $classgenerator->write($driver->get_namespace());
190
            }
191 9
            require $entityfile;
192
        }
193
194 9
        $config = ORMSetup::createConfiguration($dev_mode, $vardir . '/cache');
195 9
        $config->addFilter('softdelete', softdelete::class);
196 9
        $config->setMetadataDriverImpl($driver);
197 9
        $config->setClassMetadataFactoryName(factory::class);
198
199 9
        if (!array_key_exists('charset', $db_config)) {
200 9
            $db_config['charset'] = 'utf8';
201
        }
202
203 9
        $em = \Doctrine\ORM\EntityManager::create($db_config, $config);
204 9
        $em->getFilters()->enable('softdelete');
205 9
        $em->getEventManager()->addEventSubscriber(new subscriber);
206
207 9
        Type::overrideType(Types::DATETIME_MUTABLE, datetime::class);
208
209 9
        $midgard = midgard_connection::get_instance();
210 9
        $level = self::$loglevels[$midgard->get_loglevel()];
211 9
        if ($level === Logger::DEBUG) {
212
            $logger = new Logger('doctrine');
213
            $logger->pushHandler(new StreamHandler($midgard->config->logfilename, $level));
214
215
            $em->getConnection()->getConfiguration()->setSQLLogger(new sqllogger($logger));
216
        }
217
218 9
        self::$instance = new static($em, $driver->get_namespace());
219
    }
220
221
    /**
222
     * Get Logger instance
223
     */
224 3
    public static function log() : Logger
225
    {
226 3
        if (self::$logger === null) {
227 1
            $midgard = midgard_connection::get_instance();
228 1
            if ($midgard->config->logfilename) {
229 1
                $logdir = dirname($midgard->config->logfilename);
230 1
                if (   !is_dir($logdir)
231 1
                    && !mkdir($logdir, 0777, true)) {
232
                    throw exception::user_data('Log directory could not be created');
233
                }
234 1
                self::$logger = new Logger('midgard-portable');
235 1
                self::$logger->pushHandler(new StreamHandler($midgard->config->logfilename, self::$loglevels[$midgard->get_loglevel()]));
236
            } else {
237
                throw exception::user_data('log filename not set in config');
238
            }
239
        }
240 3
        return self::$logger;
241
    }
242
}
243