Passed
Pull Request — develop (#39)
by Kevin
02:39
created

RelationalDatabase::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 6
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Magium\Configuration\Config\Storage;
4
5
use Magium\Configuration\Config\Config;
6
use Magium\Configuration\Config\InvalidContextException;
7
use Magium\Configuration\File\Context\AbstractContextConfigurationFile;
8
use Zend\Db\Adapter\Adapter;
9
use Zend\Db\Sql\Ddl\Column\Text;
10
use Zend\Db\Sql\Ddl\Column\Varchar;
11
use Zend\Db\Sql\Ddl\Constraint\UniqueKey;
12
use Zend\Db\Sql\Ddl\CreateTable;
13
use Zend\Db\Sql\Expression;
14
use Zend\Db\Sql\Sql;
15
16
class RelationalDatabase implements StorageInterface
17
{
18
19
    const TABLE = 'magium_configuration_values';
20
21
    protected $adapter;
22
    protected $configurationFile;
23
    protected $data = [];
24
25 12
    public function __construct(
26
        Adapter $adapter,
27
        AbstractContextConfigurationFile $context
28
    )
29
    {
30 12
        $adapter->getDriver()->getConnection()->connect(); // Force a consistent connect point
31 12
        $this->adapter = $adapter;
32 12
        $this->configurationFile = $context;
33
34 12
    }
35
36 7
    public function getContexts()
37
    {
38 7
        return $this->configurationFile->getContexts();
39
    }
40
41
    /**
42
     * @param $requestedContext
43
     * @throws InvalidContextException
44
     * @return array an array of the contexts that are in the requested context's path
45
     */
46
47 8
    public function getPathForContext($requestedContext)
48
    {
49 8
        $names = [];
50
51 8
        if ($requestedContext !== Config::CONTEXT_DEFAULT) {
52 5
            $contexts = $this->getContexts();
53 5
            $xml = $this->configurationFile->toXml();
54 5
            if (!in_array($requestedContext, $contexts)) {
55 2
                throw new InvalidContextException('Unable to find context: ' . $requestedContext);
56
            }
57
58 3
            $xml->registerXPathNamespace('s', 'http://www.magiumlib.com/ConfigurationContext');
59 3
            $contexts = $xml->xpath(sprintf('//s:context[@id="%s"]', $requestedContext));
60
61 3
            $context = array_shift($contexts);
62
            do {
63
64 3
                if (!$context instanceof \SimpleXMLElement) {
65 3
                    break;
66
                }
67 3
                $names[] = (string)$context['id'];
68 3
            } while ($context = $context->xpath('..'));
69
        }
70 6
        $names[] = Config::CONTEXT_DEFAULT;
71
72 6
        return $names;
73
    }
74
75 5
    public function getValue($path, $requestedContext = Config::CONTEXT_DEFAULT)
76
    {
77 5
        if (empty($this->data)) {
78 2
            $contexts = $this->getContexts();
79 2
            foreach ($contexts as $context) {
80 2
                $sql = new Sql($this->adapter);
81 2
                $select = $sql->select(self::TABLE);
82 2
                $select->where(['context'=> $context]);
83 2
                $statement = $sql->prepareStatementForSqlObject($select);
84 2
                $resultSet = $statement->execute();
85 2
                $this->data[$context] = [];
86 2
                foreach ($resultSet as $result) {
87 2
                    $this->data[$context][$result['path']] = $result['value'];
88
                }
89
            }
90
        }
91 5
        $contextPaths = $this->getPathForContext($requestedContext);
92 5
        foreach ($contextPaths as $contextPath) {
93 5
            if (isset($this->data[$contextPath][$path])) {
94 5
                return $this->data[$contextPath][$path];
95
            }
96
        }
97 1
        return null;
98
    }
99
100 6
    public function setValue($path, $value, $requestedContext = Config::CONTEXT_DEFAULT)
101
    {
102 6
        $contexts = $this->getPathForContext($requestedContext);
103 4
        if (!in_array($requestedContext, $contexts)) {
104
            throw new InvalidContextException('Could not find the context: ' . $requestedContext);
105
        }
106
107 4
        $sql = new Sql($this->adapter);
108
109
        /*
110
         * We can't do an ON DUPLICATE UPDATE because not all adapters support that.  So we need to do a select
111
         * followed by an insert or update
112
         */
113
114 4
        if ($this->exists($sql, $path, $requestedContext)) {
115 1
            $this->doUpdate($sql, $path, $value, $requestedContext);
116
        } else {
117 4
            $this->doInsert($sql, $path, $value, $requestedContext);
118
        }
119
120 4
        $this->data[$requestedContext][$path] = $value;
121 4
    }
122
123 4
    protected function exists(Sql $sql, $path, $context)
124
    {
125 4
        $select = $sql->select(self::TABLE);
126 4
        $select->columns(['cnt' => new Expression('COUNT(*)')]);
127 4
        $select->where(['path' => $path, 'context' => $context]);
128 4
        $select = $select->getSqlString($this->adapter->getPlatform());
129
130 4
        $result = $this->adapter->query($select)->execute(  );
0 ignored issues
show
Bug introduced by
The method execute does only exist in Zend\Db\Adapter\Driver\StatementInterface, but not in Zend\Db\Adapter\Driver\R...tSet\ResultSetInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
131 4
        $check = $result->current();
132 4
        return $check && $check['cnt'] > 0;
133
    }
134
135 4 View Code Duplication
    protected function doInsert(Sql $sql, $path, $value, $context)
136
    {
137 4
        $insert = $sql->insert(self::TABLE);
138 4
        $insert->values([
139 4
            'path'      => $path,
140 4
            'value'     => $value,
141 4
            'context'   => $context
142
        ]);
143 4
        $insert = $insert->getSqlString($this->adapter->getPlatform());
144
145 4
        $this->adapter->query($insert)->execute();
0 ignored issues
show
Bug introduced by
The method execute does only exist in Zend\Db\Adapter\Driver\StatementInterface, but not in Zend\Db\Adapter\Driver\R...tSet\ResultSetInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
146 4
    }
147
148 1 View Code Duplication
    protected function doUpdate(Sql $sql, $path, $value, $context)
149
    {
150 1
        $update = $sql->update(self::TABLE);
151 1
        $update->set([
152 1
            'value' => $value
153 1
        ])->where(['path' => $path, 'context' => $context]);
154
155 1
        $update = $update->getSqlString($this->adapter->getPlatform());
156 1
        $this->adapter->query($update)->execute();
0 ignored issues
show
Bug introduced by
The method execute does only exist in Zend\Db\Adapter\Driver\StatementInterface, but not in Zend\Db\Adapter\Driver\R...tSet\ResultSetInterface.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
157 1
    }
158
159 8
    public function create()
160
    {
161 8
        $table = new CreateTable(self::TABLE);
162 8
        $table->addColumn(new Varchar('path', 255));
163 8
        $table->addColumn(new Text('value'));
164 8
        $table->addColumn(new Varchar('context', 255));
165 8
        $table->addConstraint(
166 8
            new UniqueKey(['path','context'], 'configuration_uniqueness_index')
167
        );
168
169 8
        $sql = new Sql($this->adapter);
170
171 8
        $this->adapter->query(
172 8
            $sql->buildSqlString($table),
173 8
            Adapter::QUERY_MODE_EXECUTE
174
        );
175 8
    }
176
177
}
178