Completed
Push — master ( 89c3e8...c161b3 )
by Craig
05:56 queued 40s
created

PersistedBundleHelper::doGetPersistedBundles()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 14
c 0
b 0
f 0
nc 8
nop 2
dl 0
loc 22
rs 9.4888
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Zikula package.
7
 *
8
 * Copyright Zikula Foundation - https://ziku.la/
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Zikula\Bundle\CoreBundle\Helper;
15
16
use function Composer\Autoload\includeFile;
17
use Doctrine\DBAL\Configuration;
18
use Doctrine\DBAL\Connection;
19
use Doctrine\DBAL\DriverManager;
20
use Exception;
21
use PDO;
22
use Zikula\Bundle\CoreBundle\HttpKernel\ZikulaHttpKernelInterface;
23
use Zikula\ExtensionsModule\Constant;
24
25
class PersistedBundleHelper
26
{
27
    /**
28
     * @var array the active/inactive state of each extension (extension state !== bundle state)
29
     */
30
    private $extensionStateMap = [];
31
32
    public function getPersistedBundles(ZikulaHttpKernelInterface $kernel, array &$bundles): void
33
    {
34
        try {
35
            $this->doGetPersistedBundles($kernel, $bundles);
36
        } catch (Exception $exception) {
37
            // fail silently on purpose
38
        }
39
    }
40
41
    private function doGetPersistedBundles(ZikulaHttpKernelInterface $kernel, array &$bundles): void
42
    {
43
        $conn = $this->getConnection();
44
        $conn->connect();
45
        $res = $conn->executeQuery('SELECT bundleclass, autoload, bundletype FROM bundles');
46
        foreach ($res->fetchAll(PDO::FETCH_NUM) as list($class, $autoload, $type)) {
47
            $extensionIsActive = $this->extensionIsActive($conn, $class, $type);
48
            if (!$extensionIsActive) {
49
                continue;
50
            }
51
            try {
52
                $autoload = unserialize($autoload);
53
                $this->addAutoloaders($kernel, $autoload);
54
55
                if (class_exists($class)) {
56
                    $bundles[$class] = ['all' => true];
57
                }
58
            } catch (Exception $exception) {
59
                // unable to autoload $prefix / $path
60
            }
61
        }
62
        $conn->close();
63
    }
64
65
    private function getConnection(): Connection
66
    {
67
        $connectionParams = [
68
            'url' => $_ENV['DATABASE_URL'] ?? ''
69
        ];
70
71
        return DriverManager::getConnection($connectionParams, new Configuration());
72
    }
73
74
    /**
75
     * Determine if an extension is active.
76
     */
77
    private function extensionIsActive(Connection $conn, string $class, string $type): ?bool
78
    {
79
        $extensionNameArray = explode('\\', $class);
80
        $extensionName = array_pop($extensionNameArray);
81
        if (isset($this->extensionStateMap[$extensionName])) {
82
            // used cached value
83
            $state = $this->extensionStateMap[$extensionName];
84
        } else {
85
            // load all values into class var for lookup
86
            $sql = 'SELECT m.name, m.state, m.id FROM extensions as m';
87
            $rows = $conn->executeQuery($sql);
88
            foreach ($rows as $row) {
89
                $this->extensionStateMap[$row['name']] = [
90
                    'state' => (int)$row['state'],
91
                    'id'    => (int)$row['id'],
92
                ];
93
            }
94
95
            $state = $this->extensionStateMap[$extensionName] ?? ['state' => ('T' === $type) ? Constant::STATE_INACTIVE : Constant::STATE_UNINITIALISED];
96
        }
97
98
        return in_array($state['state'], [Constant::STATE_ACTIVE, Constant::STATE_UPGRADED, Constant::STATE_TRANSITIONAL], true);
99
    }
100
101
    /**
102
     * Add autoloaders to kernel or include files from json.
103
     */
104
    public function addAutoloaders(ZikulaHttpKernelInterface $kernel, array $autoload = []): void
105
    {
106
        $srcDir = $kernel->getProjectDir() . '/src/';
107
        if (isset($autoload['psr-0'])) {
108
            foreach ($autoload['psr-0'] as $prefix => $path) {
109
                $kernel->getAutoloader()->add($prefix, $srcDir . $path);
110
            }
111
        }
112
        if (isset($autoload['psr-4'])) {
113
            foreach ($autoload['psr-4'] as $prefix => $path) {
114
                $kernel->getAutoloader()->addPsr4($prefix, $srcDir . $path);
115
            }
116
        }
117
        if (isset($autoload['classmap'])) {
118
            $kernel->getAutoloader()->addClassMap($autoload['classmap']);
119
        }
120
        if (isset($autoload['files'])) {
121
            foreach ($autoload['files'] as $path) {
122
                includeFile($path);
123
            }
124
        }
125
    }
126
}
127