Completed
Push — master ( c57039...f19613 )
by Stefan
04:50
created

EntityWithDBProperties::flushAttributes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 3
rs 10
c 1
b 0
f 0
1
<?php
2
3
/* * ********************************************************************************
4
 * (c) 2011-15 GÉANT on behalf of the GN3, GN3plus and GN4 consortia
5
 * License: see the LICENSE file in the root directory
6
 * ********************************************************************************* */
7
?>
8
<?php
9
10
/**
11
 * This file contains Federation, IdP and Profile classes.
12
 * These should be split into separate files later.
13
 *
14
 * @package Developer
15
 */
16
/**
17
 * 
18
 */
19
20
/**
21
 * This class represents an Entity with properties stored in the DB.
22
 * IdPs have properties of their own, and may have one or more Profiles. The
23
 * profiles can override the institution-wide properties.
24
 *
25
 * @author Stefan Winter <[email protected]>
26
 * @author Tomasz Wolniewicz <[email protected]>
27
 *
28
 * @license see LICENSE file in root directory
29
 *
30
 * @package Developer
31
 */
32
class EntityWithDBProperties {
33
34
    /**
35
     * This variable gets initialised with the known IdP attributes in the constructor. It never gets updated until the object
36
     * is destroyed. So if attributes change in the database, and IdP attributes are to be queried afterwards, the object
37
     * needs to be re-instantiated to have current values in this variable.
38
     * 
39
     * @var array of entity's attributes
40
     */
41
    protected $attributes;
42
43
    /**
44
     * The database to query for attributes regarding this entity
45
     * 
46
     * @var string DB type
47
     */
48
    protected $databaseType;
49
50
    /**
51
     * This variable contains the name of the table that stores the entity's options
52
     * 
53
     * @var string DB table name
54
     */
55
    protected $entityOptionTable;
56
57
    /**
58
     * column name to find entity in that table
59
     * 
60
     * @var string DB column name of entity
61
     */
62
    protected $entityIdColumn;
63
64
    /**
65
     * the unique identifier of this entity instance
66
     * Federations are identified by their TLD -> string
67
     * everything else has an integer row name in the DB -> int
68
     * 
69
     * @var int,string identifier of the entity instance
70
     */
71
    public $identifier;
72
73
    /**
74
     * the name of the entity in the current locale
75
     */
76
    public $name;
77
78
    /**
79
     * Virtual: sub-classes should define themselves what it means to become
80
     * stale
81
     */
82
    protected function updateFreshness() {
83
        
84
    }
85
86
    /**
87
     * This function returns the count of specific attributes in an IdP
88
     * This function will not retreive the values attributes (particularly important for large blobs),
89
     * it is mainly intended as a test for an attribute existance.
90
     *
91
     * @param string $optionName name of the attribute whose existence in the IdP is to be checked
92
     * @return int attribute count
93
     */
94
    public function isAttributeAvailable($optionName) {
95
        $quotedIdentifier = (!is_int($identifier) ? "\"" : "") . $this->identifier . (!is_int($identifier) ? "\"" : "");
0 ignored issues
show
Bug introduced by
The variable $identifier does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
96
        $escapedOptionName = DBConnection::escape_value($this->databaseType, $optionName);
97
        $result = DBConnection::exec($this->databaseType, "SELECT row FROM $this->entityOptionTable 
98
              WHERE $this->entityIdColumn = $quotedIdentifier AND option_name = '$escapedOptionName'");
99
        return(mysqli_num_rows($result));
100
    }
101
102
    /**
103
     * This function retrieves the IdP-wide attributes. If called with the optional parameter, only attribute values for the attribute
104
     * name in $option_name are retrieved; otherwise, all attributes are retrieved.
105
     *
106
     * @param string $option_name optionally, the name of the attribute that is to be retrieved
107
     * @return array of arrays of attributes which were set for this IdP
108
     */
109
    public function getAttributes($option_name = 0) {
110
        if ($option_name) {
111
            $returnarray = [];
112
            foreach ($this->attributes as $the_attr) {
113
                if ($the_attr['name'] == $option_name) {
114
                    $returnarray[] = $the_attr;
115
                }
116
            }
117
            return $returnarray;
118
        } else {
119
            return $this->attributes;
120
        }
121
    }
122
123
    /**
124
     * deletes all attributes in this profile except the _file ones, these are reported as array
125
     *
126
     * @return array list of row id's of file-based attributes which weren't deleted
127
     */
128
    public function beginFlushAttributes() {
129
        $quotedIdentifier = (!is_int($this->identifier) ? "\"" : "") . $this->identifier . (!is_int($this->identifier) ? "\"" : "");
130
        DBConnection::exec($this->databaseType, "DELETE FROM $this->entityOptionTable WHERE $this->entityIdColumn = $quotedIdentifier AND option_name NOT LIKE '%_file'");
131
        $this->updateFreshness();
132
        $exec_q = DBConnection::exec($this->databaseType, "SELECT row FROM $this->entityOptionTable WHERE $this->entityIdColumn = $quotedIdentifier");
133
        $return_array = [];
134
        while ($a = mysqli_fetch_object($exec_q)) {
135
            $return_array[$a->row] = "KILLME";
136
        }
137
        return $return_array;
138
    }
139
140
    /**
141
     * after a beginFlushAttributes, deletes all attributes which are in the tobedeleted array
142
     *
143
     * @param array $tobedeleted array of database rows which are to be deleted
144
     */
145
    public function commitFlushAttributes($tobedeleted) {
146
        $quotedIdentifier = (!is_int($this->identifier) ? "\"" : "") . $this->identifier . (!is_int($this->identifier) ? "\"" : "");
147
        foreach (array_keys($tobedeleted) as $row) {
148
            DBConnection::exec($this->databaseType, "DELETE FROM $this->entityOptionTable WHERE $this->entityIdColumn = $quotedIdentifier AND row = $row");
149
            $this->updateFreshness();
150
        }
151
    }
152
153
    /**
154
     * deletes all attributes of this entity from the database
155
     */
156
    public function flushAttributes() {
157
        $this->commitFlushAttributes($this->beginFlushAttributes());
158
    }
159
160
    /**
161
     * Adds an attribute for the entity instance into the database. Multiple instances of the same attribute are supported.
162
     *
163
     * @param string $attrName Name of the attribute. This must be a well-known value from the profile_option_dict table in the DB.
164
     * @param mixed $attrValue Value of the attribute. Can be anything; will be stored in the DB as-is.
165
     */
166
    public function addAttribute($attrName, $attrValue) {
167
        $quotedIdentifier = (!is_int($this->identifier) ? "\"" : "") . $this->identifier . (!is_int($this->identifier) ? "\"" : "");
168
        $escapedAttrName = DBConnection::escape_value($this->databaseType, $attrName);
169
        $escapedAttrValue = DBConnection::escape_value($this->databaseType, $attrValue);
170
        DBConnection::exec($this->databaseType, "INSERT INTO $this->entityOptionTable ($this->entityIdColumn, option_name, option_value) VALUES("
171
                . $quotedIdentifier . ", '"
172
                . $escapedAttrName . "', '"
173
                . $escapedAttrValue
174
                . "')");
175
        $this->updateFreshness();
176
    }
177
178
    protected function decodeFileAttribute($optionContent) {
179
        // suppress E_NOTICE on the following... we are testing *if*
180
        // we have a serialized value - so not having one is fine and
181
        // shouldn't throw E_NOTICE
182
        if (@unserialize($optionContent) !== FALSE) { // multi-lang
183
            $tempContent = unserialize($queryResult->option_value);
0 ignored issues
show
Bug introduced by
The variable $queryResult does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
184
            return ["lang" => $tempContent['lang'], "content" => base64_decode($tempContent['content'])];
185
        } else { // single lang, direct content
186
            return ["lang" => "", "content" => base64_decode($optionContent)];
187
        }
188
    }
189
190
    protected function retrieveOptionsFromDatabase($query, $level) {
191
        $optioninstance = Options::instance();
192
        $this->attributes = [];
193
        $attributeDbExec = DBConnection::exec($this->databaseType, $query);
194
195
        while ($attributeQuery = mysqli_fetch_object($attributeDbExec)) {
196
            // decode base64 for files (respecting multi-lang)
197
            $optinfo = $optioninstance->optionType($attributeQuery->option_name);
198
            $flag = $optinfo['flag'];
199
200
            if ($optinfo['type'] != "file") {
201
                $this->attributes[] = ["name" => $attributeQuery->option_name, "value" => $attributeQuery->option_value, "level" => $level, "row" => $attributeQuery->row, "flag" => $flag];
202
            } else {
203
                $decodedAttribute = $this->decodeFileAttribute($attributeQuery->option_value);
204
                $this->attributes[] = ["name" => $attributeQuery->option_name, "value" => ($decodedAttribute['lang'] == "" ? $decodedAttribute['content'] : serialize($decodedAttribute)), "level" => $level, "row" => $attributeQuery->row, "flag" => $flag];
205
            }
206
        }
207
    }
208
209
}
210