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