Total Complexity | 47 |
Total Lines | 285 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like EntityWithDBProperties often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use EntityWithDBProperties, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
45 | abstract class EntityWithDBProperties extends \core\common\Entity { |
||
46 | |||
47 | /** |
||
48 | * This variable gets initialised with the known IdP attributes in the constructor. It never gets updated until the object |
||
49 | * is destroyed. So if attributes change in the database, and IdP attributes are to be queried afterwards, the object |
||
50 | * needs to be re-instantiated to have current values in this variable. |
||
51 | * |
||
52 | * @var array of entity's attributes |
||
53 | */ |
||
54 | protected $attributes; |
||
55 | |||
56 | /** |
||
57 | * The database to query for attributes regarding this entity |
||
58 | * |
||
59 | * @var string DB type |
||
60 | */ |
||
61 | protected $databaseType; |
||
62 | |||
63 | /** |
||
64 | * This variable contains the name of the table that stores the entity's options |
||
65 | * |
||
66 | * @var string DB table name |
||
67 | */ |
||
68 | protected $entityOptionTable; |
||
69 | |||
70 | /** |
||
71 | * column name to find entity in that table |
||
72 | * |
||
73 | * @var string DB column name of entity |
||
74 | */ |
||
75 | protected $entityIdColumn; |
||
76 | |||
77 | /** |
||
78 | * We need database access. Be sure to instantiate the singleton, and then |
||
79 | * use its instance (rather than always accessing everything statically) |
||
80 | * |
||
81 | * @var DBConnection the instance of the default database we talk to usually |
||
82 | */ |
||
83 | protected $databaseHandle; |
||
84 | |||
85 | /** |
||
86 | * the unique identifier of this entity instance |
||
87 | * refers to the integer row name in the DB -> int; Federation has no own |
||
88 | * DB, so the identifier is of no use there -> use Fedearation->$tld |
||
89 | * |
||
90 | * @var int identifier of the entity instance |
||
91 | */ |
||
92 | public $identifier; |
||
93 | |||
94 | /** |
||
95 | * the name of the entity in the current locale |
||
96 | */ |
||
97 | public $name; |
||
98 | |||
99 | /** |
||
100 | * The constructor initialises the entity. Since it has DB properties, |
||
101 | * this means the DB connection is set up for it. |
||
102 | */ |
||
103 | public function __construct() { |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * How is the object identified in the database? |
||
113 | * @return string|int |
||
114 | * @throws Exception |
||
115 | */ |
||
116 | private function getRelevantIdentifier() { |
||
117 | switch (get_class($this)) { |
||
118 | case "core\ProfileRADIUS": |
||
119 | case "core\ProfileSilverbullet": |
||
120 | case "core\IdP": |
||
121 | return $this->identifier; |
||
122 | case "core\Federation": |
||
123 | return $this->tld; |
||
124 | case "core\User": |
||
125 | return $this->userName; |
||
126 | default: |
||
127 | throw new Exception("Operating on a class where we don't know the relevant identifier in the DB - ".get_class($this)."!"); |
||
128 | } |
||
129 | } |
||
130 | |||
131 | /** |
||
132 | * This function retrieves the entity's attributes. |
||
133 | * |
||
134 | * If called with the optional parameter, only attribute values for the attribute |
||
135 | * name in $optionName are retrieved; otherwise, all attributes are retrieved. |
||
136 | * The retrieval is in-memory from the internal attributes class member - no |
||
137 | * DB callback, so changes in the database during the class instance lifetime |
||
138 | * are not considered. |
||
139 | * |
||
140 | * @param string $optionName optionally, the name of the attribute that is to be retrieved |
||
141 | * @return array of arrays of attributes which were set for this IdP |
||
142 | */ |
||
143 | public function getAttributes(string $optionName = NULL) { |
||
144 | if ($optionName !== NULL) { |
||
145 | $returnarray = []; |
||
146 | foreach ($this->attributes as $theAttr) { |
||
147 | if ($theAttr['name'] == $optionName) { |
||
148 | $returnarray[] = $theAttr; |
||
149 | } |
||
150 | } |
||
151 | return $returnarray; |
||
152 | } |
||
153 | return $this->attributes; |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * deletes all attributes in this profile except the _file ones, these are reported as array |
||
158 | * |
||
159 | * @param string $extracondition a condition to append to the deletion query. RADIUS Profiles have eap-level or device-level options which shouldn't be purged; this can be steered in the overriding function. |
||
160 | * @return array list of row id's of file-based attributes which weren't deleted |
||
161 | */ |
||
162 | public function beginFlushAttributes($extracondition = "") { |
||
173 | } |
||
174 | |||
175 | /** |
||
176 | * after a beginFlushAttributes, deletes all attributes which are in the tobedeleted array. |
||
177 | * |
||
178 | * @param array $tobedeleted array of database rows which are to be deleted |
||
179 | * @return void |
||
180 | */ |
||
181 | public function commitFlushAttributes(array $tobedeleted) { |
||
186 | } |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * deletes all attributes of this entity from the database |
||
191 | * |
||
192 | * @return void |
||
193 | */ |
||
194 | public function flushAttributes() { |
||
195 | $this->commitFlushAttributes($this->beginFlushAttributes()); |
||
196 | } |
||
197 | |||
198 | /** |
||
199 | * Adds an attribute for the entity instance into the database. Multiple instances of the same attribute are supported. |
||
200 | * |
||
201 | * @param string $attrName Name of the attribute. This must be a well-known value from the profile_option_dict table in the DB. |
||
202 | * @param string $attrLang language of the attribute. Can be NULL. |
||
203 | * @param mixed $attrValue Value of the attribute. Can be anything; will be stored in the DB as-is. |
||
204 | * @return void |
||
205 | */ |
||
206 | public function addAttribute($attrName, $attrLang, $attrValue) { |
||
207 | $relevantId = $this->getRelevantIdentifier(); |
||
208 | $identifierType = (is_int($relevantId) ? "i" : "s"); |
||
209 | $this->databaseHandle->exec("INSERT INTO $this->entityOptionTable ($this->entityIdColumn, option_name, option_lang, option_value) VALUES(?,?,?,?)", $identifierType . "sss", $relevantId, $attrName, $attrLang, $attrValue); |
||
210 | $this->updateFreshness(); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * retrieve attributes from a database. Only does SELECT queries. |
||
215 | * @param string $query sub-classes set the query to execute to get to the options |
||
216 | * @param string $level the retrieved options get flagged with this "level" identifier |
||
217 | * @return array the attributes in one array |
||
218 | */ |
||
219 | protected function retrieveOptionsFromDatabase($query, $level) { |
||
242 | } |
||
243 | |||
244 | /** |
||
245 | * Retrieves data from the underlying tables, for situations where instantiating the IdP or Profile object is inappropriate |
||
246 | * |
||
247 | * @param string $table institution_option or profile_option |
||
248 | * @param string $row rowindex |
||
249 | * @return string|boolean the data, or FALSE if something went wrong |
||
250 | */ |
||
251 | public static function fetchRawDataByIndex($table, $row) { |
||
265 | } |
||
266 | |||
267 | /** |
||
268 | * Checks if a raw data pointer is public data (return value FALSE) or if |
||
269 | * yes who the authorised admins to view it are (return array of user IDs) |
||
270 | * |
||
271 | * @param string $table which database table is this about |
||
272 | * @param int $row row index of the table |
||
273 | * @return mixed FALSE if the data is public, an array of owners of the data if it is NOT public |
||
274 | */ |
||
275 | public static function isDataRestricted($table, $row) { |
||
321 | } |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * when options in the DB change, this can mean generated installers become stale. sub-classes must define whether this is the case for them |
||
326 | * |
||
327 | * @return void |
||
328 | */ |
||
329 | abstract public function updateFreshness(); |
||
330 | } |
||
331 |