From 574f9b1421f1c30ecc2459286bf8edd20c41f822 Mon Sep 17 00:00:00 2001 From: Dirk Riestere Date: Mon, 20 Mar 2017 21:38:22 +0100 Subject: XML parser ist implementiert und HisInOne kann jetzt gelesen werden --- .../locationinfo/inc/coursebackend.inc.php | 85 +++++++++--- .../coursebackend/coursebackend_davinci.inc.php | 21 ++- .../coursebackend/coursebackend_hisinone.inc.php | 150 +++++++++------------ 3 files changed, 148 insertions(+), 108 deletions(-) (limited to 'modules-available/locationinfo/inc') diff --git a/modules-available/locationinfo/inc/coursebackend.inc.php b/modules-available/locationinfo/inc/coursebackend.inc.php index a1566229..83e4febd 100644 --- a/modules-available/locationinfo/inc/coursebackend.inc.php +++ b/modules-available/locationinfo/inc/coursebackend.inc.php @@ -12,8 +12,10 @@ abstract class CourseBackend /** * @var array list of known backends - * $error boolean true if there was an error - * $errormsg string with the error message + * @var boolean true if there was an error + * @var string with the error message + * @var int as internal serverID + * @var string url of the service */ private static $backendTypes = false; public $error; @@ -81,11 +83,6 @@ abstract class CourseBackend return self::$backendTypes[$moduleType]; } - - /* - * TODO: Insert required methods here - */ - /** * @return string return display name of backend */ @@ -93,7 +90,7 @@ abstract class CourseBackend /** - * @returns array with parameter name as key and type as value + * @returns array with parameter name as key and and an array with type, help text and mask as value */ public abstract function getCredentials(); @@ -106,10 +103,10 @@ abstract class CourseBackend * uses json to setCredentials, the json must follow the form given in * getCredentials * - * @param string $data array with the credentials + * @param array $data with the credentials * @param string $url address of the server * @param int $serverID ID of the server - * @returns void + * @returns bool if the credentials were in the correct format */ public abstract function setCredentials($data, $url, $serverID); @@ -127,7 +124,7 @@ abstract class CourseBackend /** * Internal version of fetch, to be overridden by subclasses. * - * @param $roomIds + * @param $roomIds array with local ID as key and serverID as value * @return array a multidimensional array that uses the roomID as key * and has the schedules as string in the value */ @@ -136,9 +133,8 @@ abstract class CourseBackend /** * Method for fetching the schedule of the given rooms on a server. * - * @param int $roomId int of room ID to fetch - * @param int $serverid id of the server - * @return string|bool some jsonstring as result, or false on error + * @param array $roomId array of room ID to fetch + * @return array|bool array containing the timetables as value and roomid as key as result, or false on error */ public final function fetchSchedule($roomIDs) { @@ -148,13 +144,14 @@ abstract class CourseBackend $dbquery1 = Database::simpleQuery($q); $result = []; $sRoomIDs = []; + $newResult = []; foreach ($dbquery1->fetchAll(PDO::FETCH_ASSOC) as $row) { $sRoomID = $row['serverroomid']; $lastUpdate = $row['lastcalendarupdate']; $calendar = $row['calendar']; //Check if in cache if lastUpdate is null then it is interpreted as 1970 - if (strtotime($lastUpdate) > strtotime("-" . $this->getCacheTime() . "seconds") && $this->getCacheTime() > 0) { - $result[$row['locationid']] = json_decode($calendar); + if ($lastUpdate > strtotime("-" . $this->getCacheTime() . "seconds")) { + $newResult[$row['locationid']] = json_decode($calendar); } else { $sRoomIDs[$row['locationid']] = $sRoomID; } @@ -176,7 +173,7 @@ abstract class CourseBackend if ($results === false) { return false; } - $newResult = []; + foreach ($sRoomIDs as $location => $serverRoom) { $newResult[$location] = $results[$serverRoom]; } @@ -205,5 +202,59 @@ abstract class CourseBackend } return false; } + /** + * Query path in array-representation of XML document. + * e.g. 'path/syntax/foo/wanteditem' + * This works for intermediate nodes (that have more children) + * and leaf nodes. The result is always an array on success, or + * false if not found. + */ + function getAttributes($array, $path) + { + if (!is_array($path)) { + // Convert 'path/syntax/foo/wanteditem' to array for further processing and recursive calls + $path = explode('/', $path); + } + do { + // Get next element from array, loop to ignore empty elements (so double slashes in the path are allowed) + $element = array_shift($path); + } while (empty($element) && !empty($path)); + if (!isset($array[$element])) { + // Current path element does not exist - error + return false; + } + if (empty($path)) { + // Path is now empty which means we're at 'wanteditem' from out example above + if (!is_array($array[$element]) || !isset($array[$element][0])) { + // If it's a leaf node of the array, wrap it in plain array, so the function will + // always return an array on success + return array($array[$element]); + } + // 'wanteditem' is not a unique leaf node, return as is + // This means it's either a plain array, in case there are multiple 'wanteditem' elements on the same level + // or it's an associative array if 'wanteditem' has any sub-nodes + return $array[$element]; + } + // Recurse + if (!is_array($array[$element])) { + // We're in the middle of the requested path, but the current element is already a leaf node with no + // children - error + return false; + } + if (isset($array[$element][0])) { + // The currently handled element of the path exists multiple times on the current level, so it is + // wrapped in a plain array - recurse into each one of them and merge the results + $return = []; + foreach ($array[$element] as $item) { + $test = $this->getAttributes($item, $path); + If(gettype($test) == "array" ){ + $return = array_merge($return, $test); + } + } + return $return; + } + // Unique non-leaf node - simple recursion + return $this->getAttributes($array[$element], $path); + } } diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php index e857a26b..85d834ff 100644 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_davinci.inc.php @@ -20,7 +20,7 @@ class Coursebackend_Davinci extends CourseBackend public function checkConnection() { if ($this->location != "") { - $this->fetchArray('B206'); + $this->fetchSchedulesInternal(['B206']); return !$this->error; } $this->error = true; @@ -49,21 +49,28 @@ class Coursebackend_Davinci extends CourseBackend return 0; } + /** + * @param $response xml document + * @return bool|array array representation of the xml if possible + */ private function toArray($response) { - try { $cleanresponse = preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $response); $xml = new SimpleXMLElement($cleanresponse); $array = json_decode(json_encode((array)$xml), true); } catch (Exception $exception) { $this->error = true; - $this->errormsg = "url did not send a xml"; + $this->errormsg = "url did not answer with a xml, maybe the url is wrong or the room is wrong"; $array = false; } return $array; } + /** + * @param $roomId string name of the room + * @return array|bool if successful the arrayrepresentation of the timetable + */ private function fetchArray($roomId) { $startDate = new DateTime('monday this week'); @@ -97,18 +104,17 @@ class Coursebackend_Davinci extends CourseBackend public function fetchSchedulesInternal($roomIds) { $schedules = []; - foreach ($roomIds as $sroomId) { $return = $this->fetchArray($sroomId); if ($return === false) { return false; - } elseif (!isset($return['Lessons']['Lesson'])) { + } + $lessons = $this->getAttributes($return,'Lessons/Lesson'); + if (!$lessons) { $this->error = true; $this->errormsg = "url send a xml in a wrong format"; return false; } - $lessons = $return['Lessons']['Lesson']; - $timetable = []; foreach ($lessons as $lesson) { $date = $lesson['Date']; @@ -127,6 +133,7 @@ class Coursebackend_Davinci extends CourseBackend } $schedules[$sroomId] = $timetable; } + error_log('123'.json_encode($schedules)); return $schedules; } } diff --git a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php index 0d057bee..cef975b8 100644 --- a/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php +++ b/modules-available/locationinfo/inc/coursebackend/coursebackend_hisinone.inc.php @@ -6,23 +6,23 @@ class CourseBackend_HisInOne extends CourseBackend private $password; private $open; - //Sets the location and the login information of this client - public function setCredentials($data, $location, $serverID) + + public function setCredentials($data, $url, $serverID) { if (array_key_exists('password', $data) && array_key_exists('username', $data) && array_key_exists('role', $data) && isset($data['open'])) { $this->error = false; $this->password = $data['password']; $this->username = $data['username'] . "\t" . $data['role']; $this->open = $data['open']; - if ($location == "") { + if ($url == "") { $this->error = true; $this->errormsg = "No url is given"; return !$this->error; } if ($this->open) { - $this->location = $location . "/qisserver/services2/OpenCourseService"; + $this->location = $url . "/qisserver/services2/OpenCourseService"; } else { - $this->location = $location . "/qisserver/services2/CourseService"; + $this->location = $url . "/qisserver/services2/CourseService"; } $this->serverID = $serverID; } else { @@ -37,23 +37,25 @@ class CourseBackend_HisInOne extends CourseBackend public function checkConnection() { - if ($this->location =="") { + if ($this->location == "") { $this->error = true; $this->errormsg = "Credentials are not set"; } - $this->findUnit(42); + $this->fetchSchedulesInternal([190=>190]); return !$this->error; } - //Cache the timetables for 30 minutes ttables older than 60 are not refreshed - + /** + * @param $roomID int + * @return array|bool if successful an array with the subjectIDs that take place in the room + */ public function findUnit($roomID) { $termYear = date('Y'); - $termType = date('n'); - if ($termType > 3 && $termType < 10) { + $termType1 = date('n'); + if ($termType1 > 3 && $termType1 < 10) { $termType = 2; - } elseif ($termType > 10) { + } elseif ($termType1 > 10) { $termType = 1; $termYear = $termYear + 1; } else { @@ -96,17 +98,14 @@ class CourseBackend_HisInOne extends CourseBackend $this->error = true; $this->errormsg = $response2['soapenvBody']['soapenvFault']['faultcode'] . " " . $response2['soapenvBody']['soapenvFault']['faultstring']; return false; - } - elseif ($this->open && isset($response2['soapenvBody']['hisfindUnitResponse']['hisunits']['hisunit'])) { - $units = $response2['soapenvBody']['hisfindUnitResponse']['hisunits']['hisunit']; + } elseif ($this->open) { + $units = $this->getAttributes($response2,'soapenvBody/hisfindUnitResponse/hisunits/hisunit'); foreach ($units as $unit) { $id[] = $unit['hisid']; } - } elseif (!$this->open && isset($response2['soapenvBody']['hisfindUnitResponse']['hisunitIds'])) { - if(isset($response2['soapenvBody']['hisfindUnitResponse']['hisunitIds']['hisid'])){ - $id = $response2['soapenvBody']['hisfindUnitResponse']['hisunitIds']['hisid']; - } - } else { + } elseif (!$this->open) { + $id = $this->getAttributes($response2,'soapenvBody/hisfindUnitResponse/hisunitIds/hisid'); + } else { $this->error = true; $this->errormsg = "url send a xml in a wrong format"; $id = false; @@ -114,8 +113,10 @@ class CourseBackend_HisInOne extends CourseBackend return $id; } - //ttables older than 60 minutes are not refreshed - + /** + * @param $doc DOMDocument + * @return DOMElement + */ private function getHeader($doc) { $header = $doc->createElement('SOAP-ENV:Header'); @@ -136,6 +137,11 @@ class CourseBackend_HisInOne extends CourseBackend return $header; } + /** + * @param $request string with xml SOAP request + * @param $action string with the name of the SOAP action + * @return bool|string if successful the answer xml from the SOAP server + */ private function __doRequest($request, $action) { $header = array( @@ -172,6 +178,10 @@ class CourseBackend_HisInOne extends CourseBackend return $output; } + /** + * @param $response xml document + * @return bool|array array representation of the xml if possible + */ private function toArray($response) { try { @@ -186,22 +196,20 @@ class CourseBackend_HisInOne extends CourseBackend return $array; } - //Contstructs the Soap Header $doc is a DOMDocument this returns a DOMElement + public function getCacheTime() { return 30 * 60; } - //returns the IDs in an array for a given roomID or false if there was an error + public function getRefreshTime() { return 60 * 60; } - //This function sends a Soaprequest with the eventID and returns an array which contains much - // informations, like start and enddates for events and their name. It returns false if there was an error public function getDisplayName() { @@ -209,20 +217,17 @@ class CourseBackend_HisInOne extends CourseBackend } - //Makes a SOAP-Request as a normal POST - public function getCredentials() { - $credentials = ["username" => "string", "role" => "string", "password" => "string", "open" => "bool"]; + $credentials = ["username" => ["string", "Name used to identify on HisInOne", false], "role" =>["string", "Role used to identify on HisInOne", false], "password" => ["string", "Password for the username on HisInOne", true], "open" => ["bool", "If checked the opencourseservice interface is used", false]]; return $credentials; } - //this function transforms a xml string into an array or return false if there was an error public function fetchSchedulesInternal($param) { - if(empty($param)){ + if (empty($param)) { $this->error = true; $this->errormsg = 'No roomid was given'; } @@ -231,7 +236,7 @@ class CourseBackend_HisInOne extends CourseBackend $eventIDs = []; foreach ($param as $ID) { $unitID = $this->findUnit($ID); - if ($unitID === false) { + if ($unitID == false) { return false; } $eventIDs = array_merge($eventIDs, $unitID); @@ -240,8 +245,8 @@ class CourseBackend_HisInOne extends CourseBackend return false; } } - if(empty($eventIDs)){ - foreach ($param as $room){ + if (empty($eventIDs)) { + foreach ($param as $room) { $tTables[$room] = []; } return $tTables; @@ -260,54 +265,24 @@ class CourseBackend_HisInOne extends CourseBackend $timetable = array(); //Here I go over the soapresponse foreach ($events as $event) { - if(empty($event['hisunit']['hisplanelements']['hisplanelement'][0]['hisdefaulttext'])){ - $this->error = true; - $this->errormsg = "url returns a wrong xml"; - return false; + $name = $this->getAttributes($event,'/hisunit/defaulttext'); + if($name==false){ + //if HisInOne has no default text then there is no name + $name = ['']; } - $title = $event['hisunit']['hisplanelements']['hisplanelement'][0]['hisdefaulttext']; - foreach ($event as $subject) { - $units = $subject['hisplanelements']['hisplanelement']; - foreach ($units as $unit) { - $pdates = $unit['hisplannedDates']['hisplannedDate']; - //there seems to be a bug that gives more than one individualDates in plannedDate - //this construction catches it - if (array_key_exists('hisindividualDates', $pdates)) { - $dates = $pdates['hisindividualDates']['hisindividualDate']; - foreach ($dates as $date) { - $roomID = $date['hisroomId']; - $datum = $date['hisexecutiondate']; - if (intval($roomID) == $room && in_array($datum, $currentWeek)) { - $startTime = $date['hisstarttime']; - $endTime = $date['hisendtime']; - $json = array( - 'title' => $title, - 'start' => $datum . " " . $startTime, - 'end' => $datum . " " . $endTime - ); - array_push($timetable, $json); - } - } - } else { - foreach ($pdates as $dates2) { - $dates = $dates2['hisindividualDates']['hisindividualDate']; - foreach ($dates as $date) { - $roomID = $date['hisroomId']; - $datum = $date['hisexecutiondate']; - if (intval($roomID) == $room && in_array($datum, $currentWeek)) { - - $startTime = $date['hisstarttime']; - $endTime = $date['hisendtime']; - $json = array( - 'title' => $title, - 'start' => $datum . " " . $startTime, - 'end' => $datum . " " . $endTime - ); - array_push($timetable, $json); - } - } - } - } + $dates = $this->getAttributes($event,'/hisunit/hisplanelements/hisplanelement/hisplannedDates/hisplannedDate/hisindividualDates/hisindividualDate'); + foreach ($dates as $date) { + $roomID =$this->getAttributes($date,'/hisroomId')[0]; + $datum = $this->getAttributes($date,'/hisexecutiondate')[0]; + if (intval($roomID) == $room && in_array($datum, $currentWeek)) { + $startTime = $this->getAttributes($date,'hisstarttime')[0]; + $endTime = $this->getAttributes($date,'hisendtime')[0]; + $json = array( + 'title' => $name[0], + 'start' => $datum . " " . $startTime, + 'end' => $datum . " " . $endTime + ); + array_push($timetable, $json); } } } @@ -316,8 +291,11 @@ class CourseBackend_HisInOne extends CourseBackend return $tTables; } - //Request for a timetable with roomids as array it will be boolean false if there was an error + /** + * @param $unit int ID of the subject in HisInOne database + * @return bool|array false if there was an error otherwise an array with the information about the subject + */ public function readUnit($unit) { $doc = new DOMDocument('1.0', 'utf-8'); @@ -348,21 +326,25 @@ class CourseBackend_HisInOne extends CourseBackend if ($response2 != false) { if (isset($response2['soapenvBody']['soapenvFault'])) { $this->error = true; - $this->errormsg = $response2['soapenvBody']['soapenvFault']['faultcode'] . " " . $response2['soapenvBody']['soapenvFault']['faultstring']; + $this->errormsg = 'SOAP-Fault'.$response2['soapenvBody']['soapenvFault']['faultcode'] . " " . $response2['soapenvBody']['soapenvFault']['faultstring']; return false; } elseif (isset($response2['soapenvBody']['hisreadUnitResponse'])) { $this->error = false; $response3 = $response2['soapenvBody']['hisreadUnitResponse']; + $this->errormsg = ''; return $response3; } else { $this->error = true; - $this->errormsg = "url send a xml in a wrong format"; + $this->errormsg = "wrong url or the url send a xml in the wrong format"; return false; } } return false; } + /** + * @return array with days of the current week in datetime format + */ private function getCurrentWeekDates() { $DateArray = array(); -- cgit v1.2.3-55-g7522