1<?php 2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4/** 5 * ADT based-object base class 6 * 7 * Currently "mixed" with ActiveRecord-pattern, could be splitted 8 * 9 * @author Jörg Lützenkirchen <luetzenkirchen@leifos.com> 10 * @version $Id$ 11 * @ingroup ServicesADT 12 */ 13abstract class ilADTBasedObject 14{ 15 protected $properties = array(); // [array] 16 protected $db_errors = array(); // [array] 17 18 /** 19 * Constructor 20 * 21 * Tries to read record from DB, in accordance to current ILIAS behaviour 22 * 23 * @return self 24 */ 25 public function __construct() 26 { 27 $this->properties = $this->initProperties(); 28 29 // :TODO: to keep constructor "open" we COULD use func_get_args() 30 $this->parsePrimary(func_get_args()); 31 $this->read(); 32 } 33 34 35 // 36 // properties 37 // 38 39 /** 40 * Init properties (aka set ADT definition) 41 * 42 * @return ilADT 43 */ 44 abstract protected function initProperties(); 45 46 /** 47 * Get all properties 48 * 49 * @return array ilADT 50 */ 51 public function getProperties() 52 { 53 return $this->properties; 54 } 55 56 /** 57 * Validate 58 * 59 * @return bool 60 */ 61 public function isValid() 62 { 63 return $this->properties->isValid(); 64 } 65 66 /** 67 * Get property magic method ("get<PropertyName>()") 68 * 69 * Setters are type-specific and cannot be magic 70 * 71 * @throws Exception 72 * @param string $a_method 73 * @param mixed $a_value 74 * @return ilADT 75 */ 76 public function __call($a_method, $a_value) 77 { 78 $type = substr($a_method, 0, 3); 79 switch ($type) { 80 case "get": 81 $parsed = strtolower(preg_replace("/([A-Z])/", " $1", substr($a_method, 3))); 82 $parsed = str_replace(" ", "_", trim($parsed)); 83 if (!$this->properties->hasElement($parsed)) { 84 throw new Exception("ilADTObject unknown property " . $parsed); 85 } 86 return $this->properties->getElement($parsed); 87 88 default: 89 throw new Exception("ilADTObject unknown method " . $parsed); 90 } 91 } 92 93 94 // 95 // CRUD / active record 96 // 97 98 /** 99 * Parse incoming primary key 100 * 101 * @see __construct() 102 * @param array $a_args 103 */ 104 abstract protected function parsePrimary(array $a_args); 105 106 /** 107 * Check if currently has primary 108 * 109 * @return bool 110 */ 111 abstract protected function hasPrimary(); 112 113 /** 114 * Create new primary key, e.g. sequence 115 * 116 * @return bool 117 */ 118 abstract protected function createPrimaryKey(); 119 120 /** 121 * Init (properties) DB bridge 122 * 123 * @param ilADTGroupDBBridge $a_adt_db 124 */ 125 abstract protected function initDBBridge(ilADTGroupDBBridge $a_adt_db); 126 127 /** 128 * Init active record helper for current table, primary and properties 129 * 130 * @return ilADTActiveRecord 131 */ 132 protected function initActiveRecordInstance() 133 { 134 global $DIC; 135 136 $ilDB = $DIC['ilDB']; 137 138 if (!$this->hasPrimary()) { 139 throw new Exception("ilADTBasedObject no primary"); 140 } 141 142 $factory = ilADTFactory::getInstance(); 143 $this->adt_db = $factory->getDBBridgeForInstance($this->properties); 144 $this->initDBBridge($this->adt_db); 145 146 // use custom error handling 147 include_once "Services/ADT/classes/class.ilADTDBException.php"; 148 $ilDB->exception = "ilADTDBException"; 149 150 return $factory->getActiveRecordInstance($this->adt_db); 151 } 152 153 /** 154 * Read record 155 * 156 * @return boolean 157 */ 158 public function read() 159 { 160 if ($this->hasPrimary()) { 161 $rec = $this->initActiveRecordInstance(); 162 return $rec->read(); 163 } 164 return false; 165 } 166 167 /** 168 * Create record (only if valid) 169 * 170 * @return boolean 171 */ 172 public function create() 173 { 174 if ($this->hasPrimary()) { 175 return $this->update(); 176 } 177 178 if ($this->isValid()) { 179 if ($this->createPrimaryKey()) { 180 try { 181 $rec = $this->initActiveRecordInstance(); 182 $rec->create(); 183 } catch (ilADTDBException $e) { 184 $this->db_errors[$e->getColumn()][] = $e->getCode(); 185 return false; 186 } 187 return true; 188 } 189 } 190 return false; 191 } 192 193 /** 194 * Update record (only if valid) 195 * 196 * @return boolean 197 */ 198 public function update() 199 { 200 if (!$this->hasPrimary()) { 201 return $this->create(); 202 } 203 204 if ($this->isValid()) { 205 try { 206 $rec = $this->initActiveRecordInstance(); 207 $rec->update(); 208 } catch (ilADTDBException $e) { 209 $this->db_errors[$e->getColumn()][] = $e->getCode(); 210 return false; 211 } 212 return true; 213 } 214 return false; 215 } 216 217 /** 218 * Delete record 219 * 220 * @return boolean 221 */ 222 public function delete() 223 { 224 if ($this->hasPrimary()) { 225 $rec = $this->initActiveRecordInstance(); 226 $rec->delete(); 227 return true; 228 } 229 return false; 230 } 231 232 /** 233 * Get DB errors 234 * 235 * @return array 236 */ 237 public function getDBErrors() 238 { 239 return $this->db_errors; 240 } 241 242 /** 243 * Translate DB error codes 244 * 245 * @param array $a_codes 246 * @return array 247 */ 248 public function translateDBErrorCodes(array $a_codes) 249 { 250 global $DIC; 251 252 $lng = $DIC['lng']; 253 254 $res = array(); 255 256 foreach ($a_codes as $code) { 257 switch ($code) { 258 case MDB2_ERROR_CONSTRAINT: 259 $res[] = $lng->txt("adt_error_db_constraint"); 260 break; 261 262 default: 263 $res[] = "Unknown ADT error code " . $code; 264 break; 265 } 266 } 267 268 return $res; 269 } 270 271 /** 272 * Get translated error codes (DB, Validation) 273 * 274 * @param type $delimiter 275 * @return string 276 */ 277 public function getAllTranslatedErrors($delimiter = "\n") 278 { 279 $tmp = array(); 280 281 foreach ($this->getProperties()->getValidationErrorsByElements() as $error_code => $element_id) { 282 $tmp[] = $element_id . " [validation]: " . $this->getProperties()->translateErrorCode($error_code); 283 } 284 285 foreach ($this->getDBErrors() as $element_id => $codes) { 286 $tmp[] = $element_id . " [db]: " . implode($delimiter, $this->translateDBErrorCodes($codes)); 287 } 288 289 if (sizeof($tmp)) { 290 return get_class($this) . $delimiter . implode($delimiter, $tmp); 291 } 292 } 293} 294