Completed
Push — master ( fbb15f...90ce09 )
by Andreas
04:13
created

connection   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 207
Duplicated Lines 0 %

Test Coverage

Coverage 76.47%

Importance

Changes 17
Bugs 2 Features 1
Metric Value
eloc 83
c 17
b 2
f 1
dl 0
loc 207
ccs 65
cts 85
cp 0.7647
rs 10
wmc 27

11 Methods

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