Passed
Push — develop ( 6e52cc...15d896 )
by Kevin
05:03 queued 02:32
created

RelationalDatabase::doUpdate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 7

Duplication

Lines 10
Ratio 100 %

Code Coverage

Tests 8
CRAP Score 1

Importance

Changes 0
Metric Value
dl 10
loc 10
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 7
nc 1
nop 4
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 = null
28
    )
29
    {
30 12
        $this->adapter = $adapter;
31 12
        $this->configurationFile = $context;
32 12
        if ($context instanceof AbstractContextConfigurationFile) {
33 5
            $this->configurationFile = $context->toXml();
34 5
            $this->configurationFile->registerXPathNamespace('s', 'http://www.magiumlib.com/ConfigurationContext');
35
36
        }
37 12
    }
38
39 3
    public function getContexts()
40
    {
41 3
        $contexts = [Config::CONTEXT_DEFAULT];
42 3
        if ($this->configurationFile instanceof \SimpleXMLElement) {
43 2
            $configuredContexts = $this->configurationFile->xpath('//s:context');
44 2
            foreach ($configuredContexts as $context) {
45 2
                $contexts[] = (string)$context['id'];
46
            }
47
        }
48 3
        return $contexts;
49
    }
50
51
    /**
52
     * @param $requestedContext
53
     * @throws InvalidContextException
54
     * @return array an array of the contexts that are in the requested context's path
55
     */
56
57 8
    public function getPathForContext($requestedContext)
58
    {
59 8
        $names = [];
60
61 8
        if ($requestedContext !== Config::CONTEXT_DEFAULT
62 8
            && $this->configurationFile instanceof \SimpleXMLElement) {
63 4
            $xpath = sprintf('//s:context[@id="%s"]', $requestedContext);
64 4
            $contexts = $this->configurationFile->xpath($xpath);
65 4
            if (!$contexts) {
66 1
                throw new InvalidContextException('Unable to find context: ' . $requestedContext);
67
            }
68
69 3
            $context = array_shift($contexts);
70
            do {
71
72 3
                if (!$context instanceof \SimpleXMLElement) {
73 3
                    break;
74
                }
75 3
                $names[] = (string)$context['id'];
76 3
            } while ($context = $context->xpath('..'));
77
        }
78 7
        $names[] = Config::CONTEXT_DEFAULT;
79
80 7
        return $names;
81
    }
82
83 5
    public function getValue($path, $requestedContext = Config::CONTEXT_DEFAULT)
84
    {
85 5
        if (empty($this->data)) {
86 2
            $contexts = $this->getContexts();
87 2
            foreach ($contexts as $context) {
88 2
                $sql = new Sql($this->adapter);
89 2
                $select = $sql->select(self::TABLE);
90 2
                $select->where(['context'=> $context]);
91 2
                $statement = $sql->prepareStatementForSqlObject($select);
92 2
                $resultSet = $statement->execute();
93 2
                $this->data[$context] = [];
94 2
                foreach ($resultSet as $result) {
95 2
                    $this->data[$context][$result['path']] = $result['value'];
96
                }
97
            }
98
        }
99 5
        $contextPaths = $this->getPathForContext($requestedContext);
100 5
        foreach ($contextPaths as $contextPath) {
101 5
            if (isset($this->data[$contextPath][$path])) {
102 5
                return $this->data[$contextPath][$path];
103
            }
104
        }
105 1
        return null;
106
    }
107
108 6
    public function setValue($path, $value, $requestedContext = Config::CONTEXT_DEFAULT)
109
    {
110 6
        $contexts = $this->getPathForContext($requestedContext);
111 5
        if (!in_array($requestedContext, $contexts)) {
112 1
            throw new InvalidContextException('Could not find the context: ' . $requestedContext);
113
        }
114
115 4
        $sql = new Sql($this->adapter);
116
117
        /*
118
         * We can't do an ON DUPLICATE UPDATE because not all adapters support that.  So we need to do a select
119
         * followed by an insert or update
120
         */
121
122 4
        if ($this->exists($sql, $path, $requestedContext)) {
123 1
            $this->doUpdate($sql, $path, $value, $requestedContext);
124
        } else {
125 4
            $this->doInsert($sql, $path, $value, $requestedContext);
126
        }
127
128 4
        $this->data[$requestedContext][$path] = $value;
129 4
    }
130
131 4
    protected function exists(Sql $sql, $path, $context)
132
    {
133 4
        $select = $sql->select(self::TABLE);
134 4
        $select->columns(['cnt' => new Expression('COUNT(*)')]);
135 4
        $select->where(['path' => $path, 'context' => $context]);
136 4
        $select = $select->getSqlString($this->adapter->getPlatform());
137
138 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...
139 4
        $check = $result->current();
140 4
        return $check && $check['cnt'] > 0;
141
    }
142
143 4 View Code Duplication
    protected function doInsert(Sql $sql, $path, $value, $context)
144
    {
145 4
        $insert = $sql->insert(self::TABLE);
146 4
        $insert->values([
147 4
            'path'      => $path,
148 4
            'value'     => $value,
149 4
            'context'   => $context
150
        ]);
151 4
        $insert = $insert->getSqlString($this->adapter->getPlatform());
152
153 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...
154 4
    }
155
156 1 View Code Duplication
    protected function doUpdate(Sql $sql, $path, $value, $context)
157
    {
158 1
        $update = $sql->update(self::TABLE);
159 1
        $update->set([
160 1
            'value' => $value
161 1
        ])->where(['path' => $path, 'context' => $context]);
162
163 1
        $update = $update->getSqlString($this->adapter->getPlatform());
164 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...
165 1
    }
166
167 8
    public function create()
168
    {
169 8
        $table = new CreateTable(self::TABLE);
170 8
        $table->addColumn(new Varchar('path', 255));
171 8
        $table->addColumn(new Text('value'));
172 8
        $table->addColumn(new Varchar('context', 255));
173 8
        $table->addConstraint(
174 8
            new UniqueKey(['path','context'], 'configuration_uniqueness_index')
175
        );
176
177 8
        $sql = new Sql($this->adapter);
178
179 8
        $this->adapter->query(
180 8
            $sql->buildSqlString($table),
181 8
            Adapter::QUERY_MODE_EXECUTE
182
        );
183 8
    }
184
185
}
186