Passed
Push — master ( e9dd98...02cf1a )
by Richard
01:44
created

DatabaseCrud::tryUpdate()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 3
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
namespace Maphper\DataSource;
3
4
class DatabaseCrud {
5
    private $crudBuilder;
6
    private $whereBuilder;
7
    private $adapter;
8
    private $databaseModify;
9
    private $databaseSelect;
10
    private $table;
11
    private $primaryKey;
12
13
    public function __construct(DatabaseAdapter $adapter, DatabaseModify $databaseModify, DatabaseSelect $databaseSelect, $table, $primaryKey) {
14
        $this->adapter = $adapter;
15
        $this->databaseModify = $databaseModify;
16
        $this->databaseSelect = $databaseSelect;
17
        $this->crudBuilder = new \Maphper\Lib\CrudBuilder();
18
        $this->whereBuilder = new \Maphper\Lib\Sql\WhereBuilder();
19
        $this->table = $table;
20
        $this->primaryKey = $primaryKey;
21
    }
22
23
    public function deleteById($id) {
24
        $this->adapter->query($this->crudBuilder->delete($this->table, [$this->primaryKey[0] . ' = :id'], [':id' => $id], 1));
25
        $this->databaseSelect->deleteIDFromCache($id);
26
	}
27
28
    public function deleteByField(array $fields, array $options = []) {
29
		$query = $this->whereBuilder->createSql($fields);
30
		$this->adapter->query($this->crudBuilder->delete($this->table, $query['sql'], $query['args'], $options['limit'], null, $options['order']));
31
		$this->databaseModify->addIndex(array_keys($query['args']));
32
33
		//Clear the cache
34
		$this->databaseSelect->clearIDCache();
35
		$this->databaseSelect->clearResultCache();
36
	}
37
38
    private function getIfNew($data) {
39
        $new = false;
40
        foreach ($this->primaryKey as $k) {
41
            if (empty($data->$k)) {
42
                $data->$k = null;
43
                $new = true;
44
            }
45
        }
46
        return $new;
47
    }
48
49
    public function save($data, $tryagain = true) {
50
        $new = $this->getIfNew($data);
51
52
		try {
53
            $result = $this->insert($this->table, $this->primaryKey, $data);
54
55
			//If there was an error but PDO is silent, trigger the catch block anyway
56
			if ($result->errorCode() !== '00000') throw new \Exception('Could not insert into ' . $this->table);
57
		}
58
		catch (\Exception $e) {
59
			if (!$this->databaseModify->getTryInsertAgain($tryagain)) throw $e;
60
61
			$this->adapter->alterDatabase($this->table, $this->primaryKey, $data);
62
			$this->save($data, false);
63
		}
64
65
		$this->updatePK($data, $new);
66
		//Something has changed, clear any cached results as they may now be incorrect
67
		$this->databaseSelect->clearResultCache();
68
		$this->databaseSelect->updateCache($data, $data->{$this->primaryKey[0]});
69
	}
70
71
    private function updatePK($data, $new) {
72
        if ($new && count($this->primaryKey) == 1) $data->{$this->primaryKey[0]} = $this->adapter->lastInsertId();
73
    }
74
75
    private function checkIfUpdateWorked($data) {
76
        $updateWhere = $this->whereBuilder->createSql($data);
77
        $matched = $this->databaseSelect->findByField($updateWhere['args']);
78
        if (count($matched) == 0) throw new \InvalidArgumentException('Record inserted into table ' . $this->table . ' fails table constraints');
79
    }
80
81
	private function insert($table, array $primaryKey, $data) {
82
		$error = 0;
83
		try {
84
			$result = $this->adapter->query($this->crudBuilder->insert($table, $data));
85
		}
86
		catch (\Exception $e) {
87
			$error = 1;
88
		}
89
90
 		if ($error || $result->errorCode() !== '00000') {
91
            $result = $this->tryUpdate($table, $primaryKey, $data);
92
        }
93
94
		return $result;
95
	}
96
97
    private function tryUpdate($table, array $primaryKey, $data) {
98
        $result = $this->adapter->query($this->crudBuilder->update($table, $primaryKey, $data));
99
        if ($result->rowCount() === 0) $this->checkIfUpdateWorked($data);
100
101
        return $result;
102
    }
103
}
104