Passed
Push — master ( 24a79d...8f7b23 )
by Andreas
03:17
created

connection   A

Complexity

Total Complexity 28

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Test Coverage

Coverage 78.56%

Importance

Changes 18
Bugs 2 Features 1
Metric Value
eloc 88
c 18
b 2
f 1
dl 0
loc 201
ccs 66
cts 84
cp 0.7856
rs 10
wmc 28

12 Methods

Rating   Name   Duplication   Size   Complexity  
A get_parameter() 0 6 2
A invalidate_cache() 0 4 2
A generate_guid() 0 3 1
A set_autostart() 0 3 1
A initialize() 0 18 2
A get_user() 0 3 1
A get_em() 0 6 2
A log() 0 17 5
A set_user() 0 6 2
A __construct() 0 4 1
A get_fqcn() 0 6 2
B startup() 0 46 7
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
use Doctrine\DBAL\Logging\Connection as connection_logger;
26
use Doctrine\DBAL\Logging\Middleware;
27
28
class connection
29
{
30
    private static ?Logger $logger = null;
31
32
    /**
33
     * Loglevel translation table.
34
     *
35
     * The semantics of info and notice/message are unfortunately reversed between Monolog
36
     * and Midgard, so it looks a bit confusing..
37
     */
38
    private static array $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
    private static bool $autostart = true;
51
52
    /**
53
     * Initialization parameters
54
     */
55
    private static array $parameters = [];
56
57
    private ?user $user = null;
58
59
    private string $namespace;
60
61
    protected EntityManager $em;
62
63
    protected static ?self $instance = null;
64
65 9
    public function __construct(EntityManager $em, string $namespace)
66
    {
67 9
        $this->em = $em;
68 9
        $this->namespace = $namespace;
69
    }
70
71 166
    public static function get_em() : EntityManager
72
    {
73 166
        if (self::$instance === null) {
74
            throw new \Exception('Not initialized');
75
        }
76 166
        return self::$instance->em;
77
    }
78
79 100
    public static function get_user() : ?user
80
    {
81 100
        return self::$instance->user;
82
    }
83
84 8
    public static function set_user(user $user = null)
85
    {
86 8
        if (self::$instance === null) {
87
            throw new \Exception('Not initialized');
88
        }
89 8
        self::$instance->user = $user;
90
    }
91
92 170
    public static function get_fqcn(string $classname) : string
93
    {
94 170
        if (self::$instance->namespace) {
95 170
            return self::$instance->namespace . '\\' . $classname;
96
        }
97
        return $classname;
98
    }
99
100
    /**
101
     * Generate a new GUID
102
     */
103 116
    public static function generate_guid() : string
104
    {
105 116
        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 9
    public static function initialize(driver $driver, array $db_config, bool $dev_mode = false)
130
    {
131 9
        $vardir = $driver->get_vardir();
132
133 9
        $mgd_config = new config;
134 9
        $mgd_config->vardir = $vardir;
135 9
        $mgd_config->cachedir = $vardir . '/cache';
136 9
        $mgd_config->blobdir = $vardir . '/blobs';
137 9
        $mgd_config->sharedir = $vardir . '/schemas';
138 9
        $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 9
        midgard_connection::get_instance()->open_config($mgd_config);
143
144 9
        self::$parameters = ['driver' => $driver, 'db_config' => $db_config, 'dev_mode' => $dev_mode];
145 9
        if (self::$autostart) {
146 9
            static::startup();
147
        }
148
    }
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 9
    public static function startup()
162
    {
163 9
        if (empty(self::$parameters)) {
164
            throw new \RuntimeException('Not initialized');
165
        }
166 9
        $driver = self::$parameters['driver'];
167 9
        $db_config = self::$parameters['db_config'];
168 9
        $dev_mode = self::$parameters['dev_mode'];
169 9
        $vardir = $driver->get_vardir();
170
        // generate and include entities file if its a fresh namespace
171
        // otherwise it should be included already
172 9
        if ($driver->is_fresh_namespace()) {
173 9
            $entityfile = $vardir . '/mgdschema_classes.php';
174 9
            if ($dev_mode || !file_exists($entityfile)) {
175 9
                $classgenerator = new classgenerator($driver->get_manager(), $entityfile, $dev_mode);
176 9
                $classgenerator->write($driver->get_namespace());
177
            }
178 9
            require $entityfile;
179
        }
180
181 9
        $config = ORMSetup::createConfiguration($dev_mode, $vardir . '/cache');
182 9
        $config->addFilter('softdelete', softdelete::class);
183 9
        $config->setMetadataDriverImpl($driver);
184 9
        $config->setClassMetadataFactoryName(factory::class);
185
186 9
        $midgard = midgard_connection::get_instance();
187 9
        $level = self::$loglevels[$midgard->get_loglevel()];
188 9
        if ($level === Logger::DEBUG) {
189
            $logger = new Logger('doctrine');
190
            $logger->pushHandler(new StreamHandler($midgard->config->logfilename, $level));
191
            $config->setMiddlewares([new Middleware($logger)]);
192
        }
193
194 9
        if (!array_key_exists('charset', $db_config)) {
195 9
            $db_config['charset'] = 'utf8';
196
        }
197
198 9
        $connection = \Doctrine\DBAL\DriverManager::getConnection($db_config, $config);
199 9
        $em = new EntityManager($connection, $config);
200 9
        $em->getFilters()->enable('softdelete');
201 9
        $em->getEventManager()->addEventSubscriber(new subscriber);
202
203 9
        Type::overrideType(Types::DATETIME_MUTABLE, datetime::class);
204 9
        Type::overrideType(Types::DATE_MUTABLE, datetime::class);
205
206 9
        self::$instance = new static($em, $driver->get_namespace());
207
    }
208
209
    /**
210
     * Get Logger instance
211
     */
212 3
    public static function log() : Logger
213
    {
214 3
        if (self::$logger === null) {
215 1
            $midgard = midgard_connection::get_instance();
216 1
            if ($midgard->config->logfilename) {
217 1
                $logdir = dirname($midgard->config->logfilename);
218 1
                if (   !is_dir($logdir)
219 1
                    && !mkdir($logdir, 0777, true)) {
220
                    throw exception::user_data('Log directory could not be created');
221
                }
222 1
                self::$logger = new Logger('midgard-portable');
223 1
                self::$logger->pushHandler(new StreamHandler($midgard->config->logfilename, self::$loglevels[$midgard->get_loglevel()]));
0 ignored issues
show
Bug introduced by
The method pushHandler() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

223
                self::$logger->/** @scrutinizer ignore-call */ 
224
                               pushHandler(new StreamHandler($midgard->config->logfilename, self::$loglevels[$midgard->get_loglevel()]));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
224
            } else {
225
                throw exception::user_data('log filename not set in config');
226
            }
227
        }
228 3
        return self::$logger;
229
    }
230
}
231