RelationalDatabase::getValue()   B
last analyzed

Complexity

Conditions 6
Paths 6

Size

Total Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 17
CRAP Score 6

Importance

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