/** * build an array of collection data from XML, so that it may be fed to * syncDBCollection() * if a single xsi:nil element is found, then return an empty array, * signifying deletion of all elements * if no element is found, then return null, signifying no changes to * existing elements * otherwise, return an array of new element so that they may be synced * with the existing ones (i.e. add/remove accordingly) * * @xml SimpleXMLElement the resource's XML representation root element * @path string XPath to the elements that belong to the collection in * question * @key string the key that will be used to put data in the array * * @return string[] * @access protected */ protected function buildCollection($xml, $path, $key) { $xmli = @$xml->xpath($path); if ($xmli === false) { return null; } if (count($xmli) === 1 && $xmli[0]->attributes(RestAPIHelper::XMLNS_XSI())->nil && strval($xmli[0]->attributes(RestAPIHelper::XMLNS_XSI())->nil) == "true") { return array(); } elseif (count($xmli) === 0) { return null; } else { $data = array(); } $i = 0; foreach ($xmli as $xml) { if ($xml->attributes(RestAPIHelper::XMLNS_XSI())->nil && strval($xml->attributes(RestAPIHelper::XMLNS_XSI())->nil) != "true" || is_null($xml->attributes(RestAPIHelper::XMLNS_XSI())->nil)) { if ($key == "mw") { $id = '{"name": "' . str_replace('"', '\'', strval($xml)) . '", "link": "' . strval($xml->attributes()->link) . '"}'; } elseif ($key == "url") { $id = '{"id": "' . strval($xml->attributes()->id) . '", "type": "' . strval($xml->attributes()->type) . '", "url": "' . strval($xml) . '", "title": "' . strval($xml->attributes()->title) . '"}'; } elseif ($key == "license") { $lic = array("licenseid" => "", "name" => "", "group" => "", "title" => "", "url" => "", "comment" => ""); foreach ($xml->attributes() as $lk => $lv) { $lic[strval($lk)] = strval($lv); } $cv = $xml->attributes()->id; $lic["licenseid"] = trim(strval($cv)); if ($lic["licenseid"] === "") { $lic["licenseid"] = "0"; } $cv = $xml->xpath("./license:comment"); $lic["comment"] = count($cv) > 0 ? strval($cv[0]) : ""; $cv = $xml->xpath("./license:url"); $lic["url"] = count($cv) > 0 ? strval($cv[0]) : ""; $cv = $xml->xpath("./license:title"); $lic["title"] = count($cv) > 0 ? strval($cv[0]) : ""; $id = json_encode($lic); } else { $id = strval($xml->attributes()->id); } if ($id != "") { $data[$key . $i] = $id; $i = $i + 1; } } } return $data; }
/** * implementation of abstract parse() operation from RestXMLParser. * * @xml SimpleXMLElement the root element of the application XML representation * * @return Default_Model_Researcher * @access public */ public function parse($xml) { if (!is_null($this->_user)) { $person = new Default_Model_Researcher(); try { $xml = new SimpleXMLElement($xml); } catch (Exception $e) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; $this->_extError = $e->getMessage(); return $person; } $xmli = $xml->xpath('//person:person'); if (count($xmli) === 0) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; return $person; } $xml = $xmli[0]; if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { if ($xml->attributes()->id) { $person->id = strval($xml->attributes()->id); } else { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; $this->_extError = 'Resource ID missing'; return $person; } } if ($xml->attributes()->nodissemination) { $person->noDissemination = strval($xml->attributes()->nodissemination) === "true" ? true : false; } if ($xml->attributes()->cname) { $person->cname = strval($xml->attributes()->cname); } $firstname = $this->el($xml, "person:firstname"); if (!is_null($firstname) && trim(strval($firstname)) !== "") { $person->firstName = trim(strval($firstname)); } $lastname = $this->el($xml, "person:lastname"); if (!is_null($lastname) && trim(strval($lastname)) !== "") { $person->lastName = trim(strval($lastname)); } $gender = $this->el($xml, "person:gender"); if (!is_null($gender)) { if (trim(strval($gender->attributes(RestAPIHelper::XMLNS_XSI())->nil)) === "true") { $person->gender = 'n/a'; } elseif (trim(strval($gender)) !== "") { if (trim(strtolower(strval($gender))) === "male") { $person->gender = "male"; } elseif (trim(strtolower(strval($gender))) === "female") { $person->gender = "female"; } } } if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $person->dateInclusion = date("Y-m-d"); $person->addedByID = $this->_parent->getUser()->id; } $person->lastUpdated = date('Y-m-d'); $institute = trim(strval($this->el($xml, "person:institute"))); if (!is_null($institute)) { $person->institution = trim(strval($institute)); } $country = $this->el($xml, "regional:country"); if (!is_null($country) && trim(strval($country->attributes()->id)) !== "") { $person->countryID = trim(strval($country->attributes()->id)); } $role = $this->el($xml, "person:role"); if (!is_null($role) && trim(strval($role->attributes()->id)) !== "") { $person->positionTypeID = trim(strval($role->attributes()->id)); } $image = $this->el($xml, "person:image"); $removeImageCache = false; if (!is_null($image)) { if (trim(strval($image->attributes(RestAPIHelper::XMLNS_XSI())->nil)) === "true") { $person->clearImage(); $removeImageCache = true; } else { if (!is_null($image->attributes()->type) && trim(strval($image->attributes()->type)) === "base64") { // image is given as byte64 encoded string if (trim(strval($image)) != '') { $person->image = pg_escape_bytea(trim(strval($image))); $removeImageCache = true; } } else { // image is given as URL if (trim(parse_url(strval($image), PHP_URL_SCHEME)) == '') { // no URL scheme present; assume uploaded file though // portal's uploadimage action in AppsController if (trim(strval($image)) != '') { try { $person->image = pg_escape_bytea(base64_encode(file_get_contents(APPLICATION_PATH . "/../public/" . trim(strval($image))))); $removeImageCache = true; } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $person; } } } else { // URL scheme present; assume remote file if (trim(strval($image)) != '') { try { $person->image = pg_escape_bytea(base64_encode(file_get_contents(trim(strval($image))))); $removeImageCache = true; } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $person; } } } } } } if ($removeImageCache === true) { if ($person->id != '' && file_exists(APPLICATION_PATH . "/../cache/ppl-image-" . $person->id . ".png")) { unlink(APPLICATION_PATH . "/../cache/ppl-image-" . $person->id . ".png"); } } $person->save(); if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { //remove existing contact info $conts = new Default_Model_Contacts(); $conts->filter->researcherid->equals($person->id); $conts->refresh(); for ($i = count($conts->items) - 1; $i >= 0; $i--) { $conts->remove($conts->items[$i]); } } //add new contact info $cts = new Default_Model_ContactTypes(); $cts->refresh(); $xmli = $xml->xpath("//person:contact"); $conts2 = new Default_Model_Contacts(); foreach ($xmli as $x) { if (trim(strval($x)) !== '') { $cont = new Default_Model_Contact(); $cont->researcherID = $person->id; $ct = trim(strval($x->attributes()->type)); $ctid = null; for ($i = 0; $i < count($cts->items); $i++) { if (strtolower($ct) == strtolower($cts->items[$i]->description)) { $ctid = $cts->items[$i]->id; break; } } if (!is_null($ctid)) { $cont->contactTypeID = $ctid; } else { $cont->contactTypeID = 7; //e-mail by default } $cont->data = trim(strval($x)); if (strval($x->attributes()->primary) === "true") { $cont->isPrimary = true; } $conts2->filter->data->equals($cont->data)->and($conts2->filter->contacttypeid->equals(7))->and($conts2->filter->researcherid->notequals($person->id)); $conts2->refresh("xml"); if (count($conts2->items) == 0) { $cont->save(); } else { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = "e-mail address `" . $cont->data . "' already exists"; return $person; } } } if ($this->_parent->getMethod() === RestMethodEnum::RM_POST || $this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $xrels = $xml->xpath("person:relation"); $ps = new Default_Model_Researchers(); $ps->filter->id->equals($person->id); $p = null; if (count($ps->items) > 0) { $p = $ps->items[0]; } if ($p !== null) { $rels = array(); if (count($xml->xpath('person:relation[@xsi:nil="true"]')) === 0) { foreach ($xrels as $x) { $targuid = trim(strval($x->attributes()->targetguid)); $subguid = trim(strval($x->attributes()->subjectguid)); $rel = array("id" => trim(strval($x->attributes()->id)), "parentid" => trim(strval($x->attributes()->parentid))); if ($targuid === "") { $rel["subjectguid"] = $subguid; } else { if ($subguid === "") { $rel["targetguid"] = $targuid; } } if ($rel["parentid"] === "") { $rel["parentid"] = null; } $rels[] = $rel; } } try { $res = PersonRelations::syncRelations($p->guid, $this->_user->id, $rels); } catch (Exception $ex) { $res = $ex->getMessage(); } if (is_string($res)) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $res; return $p; } } } } $this->_error = RestErrorEnum::RE_OK; return $person; }
/** * implementation of abstract parse() operation from RestXMLParser. * Notes: * - Simple application properties are set in the application model directly * from the XML * - Simple collections of associations of the appliation to various other * entities such as middlewares, discipline, etc. are synchronized using * syncDBCollection(), by putting information from the XML into arrays * (hash-tables) and then uniformly passing info from the array to models * - Complicated collections of associations such as application contact * metadata and publication have dedicated functions, yet the XML -> array * -> Model logic still stands * * @xml SimpleXMLElement the root element of the application XML representation * * @return Default_Model_Application * @access public */ public function parse($xml) { global $application; if (!is_null($this->_user)) { $app = new Default_Model_Application(); try { $xml = new SimpleXMLElement($xml); } catch (Exception $e) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; return $app; } $this->_xml = $xml; // basic properties $xmli = $xml->xpath('//application:application'); if (count($xmli) === 0) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; return $app; } $xml = $xmli[0]; if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { if ($xml->attributes()->id) { $app->id = strval($xml->attributes()->id); $db = $application->getBootstrap()->getResource('db'); $db->setFetchMode(Zend_Db::FETCH_OBJ); $r = $db->query('SELECT guid FROM applications WHERE id = ' . $app->id)->fetchAll(); if (count($r) > 0) { $app->guid = $r[0]->guid; } } else { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; return $app; } } $sync = false; if ($this->_parent->getParam('sync') === "true") { if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { if ($xml->attributes()->id) { $id = strval($xml->attributes()->id); $apps = new Default_Model_Applications(); $apps->filter->id->equals($id); if (count($apps->items) > 0) { if ($this->_parent->canSync($apps->items[0])) { $sync = true; } } } } else { if ($this->_parent->canSync(null)) { $sync = true; } } } if ($xml->attributes()->tool) { $app->tool = strval($xml->attributes()->tool) === "true" ? true : false; } if (!$sync) { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $app->addedBy = $this->_parent->getUser()->id; } } else { $addedby = $this->el($xml, "application:addedby"); if ($addedby && $addedby->attributes()->id) { $app->addedBy = strval($addedby->attributes()->id); } else { $app->addedBy = $this->_parent->getUser()->id; } } $owner = $this->el($xml, "application:owner"); $ownerID = ''; // IF NOT SYNCING: // if an owner is specified, and either the user has the permission // to set it or the user is a service adding a new application, then // do set the owner, or else set the owner to be the same user as the // one that makes the request if this is a new application, otherwise // let it be // IF SYNCING: // set the owner as if specified. if not, set it to be the same as // the addedby property if (!$sync) { if (!is_null($owner) && !is_null($owner->attributes()->id)) { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { if ($this->_user->accountType == 1 || $this->_parent->userIsAdmin()) { $ownerID = strval($owner->attributes()->id); } else { $ownerID = $app->addedBy; } } elseif ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { if ($this->_user->privs->canGrantOwnership($app)) { $ownerID = strval($owner->attributes()->id); } } } else { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $ownerID = $app->addedBy; } } } else { if (!is_null($owner) && !is_null($owner->attributes()->id)) { $ownerID = strval($owner->attributes()->id); } else { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $ownerID = $app->addedBy; } } } if ($ownerID != '') { $app->ownerID = $ownerID; } if ($xml->attributes()->tagPolicy) { if ($this->_parent->userIsAdmin() || $newapp || $this->_parent->getUser()->id === $app->addedBy || $this->_parent->getUser()->id === $app->ownerID) { $app->tagPolicy = strval($xml->attributes()->tagPolicy); } } $nameError = ''; $nameReason = ''; if ($this->_user->privs->canModifyApplicationName($app)) { if (!is_null($this->el($xml, "application:name"))) { if (validateAppName(preg_replace("/-DELETED-.{8}-.{4}-.{4}-.{4}-.{12}/", "", strval($this->el($xml, "application:name"))), $nameError, $nameReason, $this->_parent->getMethod() === RestMethodEnum::RM_POST ? $app->id : null)) { $app->name = strval($this->el($xml, "application:name")); } else { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = "Invalid application name. " . strip_tags($nameReason); return $app; } } } if ($this->_user->privs->canModifyApplicationDescription($app)) { $app->description = strval($this->el($xml, "application:description")); } if ($this->_user->privs->canModifyApplicationAbstract($app)) { $app->abstract = strval($this->el($xml, "application:abstract")); } if ($this->_user->privs->canModifyApplicationStatus($app)) { $status = $this->el($xml, "application:status"); if ($status && $status->attributes()->id) { $app->statusID = strval($status->attributes()->id); } } if (!$sync) { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $app->dateAdded = date('Y-m-d H:i:s'); } } else { $dateAdded = $this->el($xml, "application:addedOn"); if ($dateAdded) { $app->dateAdded = strval($dateAdded); } else { if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT) { $app->dateAdded = date('Y-m-d H:i:s'); } } } if (!$sync) { $app->lastUpdated = date('Y-m-d H:i:s'); } else { $lastUpdated = $this->el($xml, "application:lastUpdated"); if ($lastUpdated) { $app->lastUpdated = strval($lastUpdated); } else { $app->lastUpdated = date('Y-m-d H:i:s'); } } if ($this->_parent->userIsAdmin()) { if ($sync) { if ($xml->attributes()->moderated) { $app->moderated = strval($xml->attributes()->moderated); } if ($app->moderated) { $app->modInfo->moddedBy = strval($this->el($xml, "application:moderator")->attributes()->id); $app->modInfo->moddedOn = $xml->moderatedOn; $app->modInfo->modReason = $xml->moderationReason; } } } if ($this->_parent->userIsAdmin() || $this->_user->privs->canDeleteApplication($app)) { if ($sync) { if ($xml->attributes()->deleted) { $app->deleted = strval($xml->attributes()->deleted); } if ($app->deleted) { $app->delInfo->deletedBy = strval($this->el($xml, "application:deleter")->attributes()->id); $app->delInfo->deletedOn = $xml->deletedOn; } } } // also set extended attributes, like deleted, moderated, tags, // etc. when syncing, which would normaly be ignored since they are // set via separate resources // if ( $sync ) { // TODO: add extra sync code // } if ($this->_user->privs->canModifyApplicationLogo($app)) { $logo = $this->el($xml, "application:logo"); $removeLogoCache = false; if (!is_null($logo)) { if ($logo->attributes(RestAPIHelper::XMLNS_XSI())->nil === "true") { $app->clearLogo(); $removeLogoCache = true; } else { if ($logo->attributes()->type && strval($logo->attributes()->type) === "base64") { // logo is given as byte64 encoded string if (strval($logo) != '') { $app->logo = pg_escape_bytea(strval($logo)); $removeLogoCache = true; } } else { // logo is given as URL if (parse_url(strval($logo), PHP_URL_SCHEME) == '') { // no URL scheme present; assume uploaded file though // portal's uploadlogo action in AppsController if (strval($logo) != '') { try { $app->logo = pg_escape_bytea(base64_encode(file_get_contents(APPLICATION_PATH . "/../public/" . strval($logo)))); $removeLogoCache = true; } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $app; } } } else { // URL scheme present; assume remote file if (strval($logo) != '') { try { $app->logo = pg_escape_bytea(base64_encode(file_get_contents(strval($logo)))); $removeLogoCache = true; } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $app; } } } } } } if ($removeLogoCache === true) { $logocachename = APPLICATION_PATH . "/../cache/app-logo-" . $app->id . ".png"; if ($app->id != '' && file_exists($logocachename)) { // invalidate logo cache unlink($logocachename); // re-build logo cache $flogo = fopen($logocachename, "w"); fwrite($flogo, base64_decode(pg_unescape_bytea($app->logo))); fclose($flogo); $logocachename2 = str_replace("/app-logo", "/55x55/app-logo", $logocachename); $logocachename3 = str_replace("/app-logo", "/100x100/app-logo", $logocachename); $logocachename2 = str_replace(".png", ".jpg", $logocachename2); $logocachename3 = str_replace(".png", ".jpg", $logocachename3); `convert -background white -flatten -strip -interlace Plane -quality 80 -scale 55x55 {$logocachename} {$logocachename2}`; `convert -background white -flatten -strip -interlace Plane -quality 80 -scale 100x100 {$logocachename} {$logocachename3}`; } } } //Set metatype of application (0: software 1: vappliance 2:swappliance ) if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT || $this->_parent->getMethod() === RestMethodEnum::RM_POST) { if (is_numeric(strval($xml->attributes()->metatype)) && intval(strval($xml->attributes()->metatype)) >= 0 && intval(strval($xml->attributes()->metatype)) < 3) { $app->metatype = intval(strval($xml->attributes()->metatype)); } else { $app->metatype = 0; } } if ($this->_parent->getMethod() === RestMethodEnum::RM_PUT && (count($xml->xpath("//application:category")) == 0 || count($xml->xpath("//discipline:discipline")) == 0 || $app->abstract == '' || $app->description == '')) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; $this->_extError = "One ore more required entities are missing or contain no data."; return $app; } else { $app->save(); } // handle tags separetely through dedicated resource classes // thus avoiding re-implementing complicated permission checks if (count($xml->xpath('//application:tag[@xsi:nil="true"]')) != 0) { // nil element specified; remove all tags try { $taglist = new RestAppTagList(array('id' => $app->id)); $xml2 = new SimpleXMLElement(strval($taglist->get())); foreach ($xml2->xpath('//application:tag') as $tag) { $t = new RestAppTagItem(array('tid' => strval($t->attributes()->id)), $taglist); $t->delete(); } } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $app; } } elseif (count($xml->xpath('//application:tag')) > 0) { // non-nil element specified; synchronize tags try { //add new $newtags = array(); foreach ($xml->xpath('//application:tag') as $tag) { if (strval($tag->attributes()->system) !== "true") { $tagval = $tag->asXML(); // TODO: formalize the appdb:appdb head in a constant // and search for other places in the API lib where this should // be done as well $tagval = '<appdb:appdb xmlns:appdb="http://appdb.egi.eu/api/' . $this->_parent->getParam('version') . '/appdb" xmlns:application="http://appdb.egi.eu/api/' . $this->_parent->getParam('version') . '/application">' . $tagval . '</appdb:appdb>'; $taglist = new RestAppTagList(array_merge($this->_parent->getParams(), array('id' => $app->id, 'data' => $tagval))); $tagres = RestAPIHelper::wrapResponse(strval($taglist->get())); $tagxml = new SimpleXMLElement(strval($tagres)); $tagxml = $tagxml->xpath("//application:tag"); $found = false; $tval = new SimpleXMLElement($tagval); $tval = $tval->xpath("//application:tag"); $tval = strval($tval[0]); foreach ($tagxml as $tt) { if (strval($tt) === $tval) { $found = true; break; } } if (!$found) { $taglist->put(); } $newtags[] = strval($tag); } } //remove non-existent $taglist = new RestAppTagList(array('id' => $app->id)); $tagsxml = strval($taglist->get()); $tagsxml = '<appdb:appdb xmlns:appdb="http://appdb.egi.eu/api/' . $this->_parent->getParam('version') . '/appdb" xmlns:application="http://appdb.egi.eu/api/' . $this->_parent->getParam('version') . '/application">' . $tagsxml . '</appdb:appdb>'; $xml2 = new SimpleXMLElement($tagsxml); foreach ($xml2->xpath('//application:tag[not(@system="true")]') as $tag) { if (!in_array(strval($tag), $newtags)) { $t = new RestAppTagItem(array_merge($this->_parent->getParams(), array('tid' => strval($t->attributes()->id))), $taglist); $t->delete(); } } } catch (Exception $e) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $e->getMessage(); return $app; } } // if no application:tag element specified, then ignore any existing tags (insert xor partial update) if ($this->_user->privs->canModifyApplicationCategory($app)) { $data = $this->buildCollection($xml, "//application:category", "categoryID"); $this->syncDBCollection("appid", $app->id, "categoryid", "AppCategories", "AppCategory", $data); } /* set primary category */ if (count($xml->xpath('//application:category[@primary="true"]')) > 0) { $catid = $xml->xpath('//application:category[@primary="true"]'); $catid = strval($catid[0]->attributes()->id); // This is MUCH faster than using the model db()->query("UPDATE appcategories SET isprimary = TRUE WHERE categoryid = ? AND appid = ?", array($catid, $app->id)); // $cats = new Default_Model_AppCategories(); // $cats->filter->appid->equals($app->id)->and($cats->filter->categoryid->equals($catid)); // if ( count($cats->items) > 0 ) { // $cat = $cats->items[0]; // $cat->isPrimary = true; // $cat->save(); // } } /* */ if ($this->_user->privs->canModifyApplicationLanguage($app)) { $data = $this->buildCollection($xml, "//application:language", "proglangID"); $this->syncDBCollection("appid", $app->id, "proglangid", "AppProgLangs", "AppProgLang", $data); } if ($this->_user->privs->canModifyApplicationDiscipline($app)) { $data = $this->buildCollection($xml, "//discipline:discipline", "disciplineID"); $this->syncDBCollection("appid", $app->id, "disciplineid", "AppDisciplines", "AppDiscipline", $data); } if ($this->_user->privs->canModifyApplicationVO($app) && trim($app->metatype) != "2") { //Do not allow editing for software appliances $data = $this->buildCollection($xml, "//vo:vo", "vo"); $this->syncDBCollection("appid", $app->id, "void", "AppVOs", "AppVO", $data, "vo"); } if ($this->_user->privs->canModifyApplicationMiddleware($app)) { $data = $this->buildCollection($xml, "//middleware:middleware", "mw"); $this->syncDBCollection("appid", $app->id, "middlewareid", "AppMiddlewares", "AppMiddleware", $data, "mw"); } if ($this->_parent->method === RestMethodEnum::RM_POST && $this->_user->privs->canAssociatePersonToApplication($app)) { $data = $this->buildCollection($xml, "//application:contact", "scicon"); $this->syncDBCollection("appid", $app->id, "researcherid", "ResearchersApps", "ResearchersApp", $data, "scicon"); $data = null; $i = 0; $xmli = $xml->xpath("//application:contact/application:contactItem"); if (count($xmli) != 0) { $data = array(); foreach ($xmli as $x) { if ($x->attributes(RestAPIHelper::XMLNS_XSI())->nil === "true") { $data = array(); break; } else { $xp = $x->xpath("parent::*"); $data['cntpnt' . $i] = '{"researcherid": "' . strval($xp[0]->attributes()->id) . '", "itemtype": "' . strval($x->attributes()->type) . '", "itemid": "' . strval($x->attributes()->id) . '", "item": "' . strval($x) . '"}'; $i = $i + 1; } } } if (!is_null($data)) { $this->syncAppContactItems($app->id, $data); } } if ($this->_user->privs->canModifyApplicationCountry($app)) { $data = $this->buildCollection($xml, "//regional:country", "countryid"); $this->syncDBCollection("appid", $app->id, "countryid", "AppManualCountries", "AppManualCountry", $data); } if ($this->_user->privs->canModifyApplicationURLs($app)) { $data = $this->buildCollection($xml, "//application:url", "url"); $this->syncDBCollection("appid", $app->id, "id", "AppUrls", "AppUrl", $data, "url"); } if ($this->_user->privs->canModifyApplicationLicenses($app)) { $data = $this->buildCollection($xml, "//application:license", "license"); if (is_null($data)) { $data = array(); } $this->syncDBCollection("appid", $app->id, "licenseid", "AppLicenses", "AppLicense", $data, "license"); } if ($this->_user->privs->canModifyApplicationDocuments($app)) { $xmli = $xml->xpath("publication:publication"); $docdata = null; if (count($xmli) != 0) { $docdata = array(); foreach ($xmli as $x) { if (strval($x->attributes(RestAPIHelper::XMLNS_XSI())->nil) === "true") { $docdata = array(); break; } $docdatum = array(); $docdatum['id'] = strval($x->attributes()->id); $this->pubprop($x, "title", $docdatum); $this->pubprop($x, "url", $docdatum); $this->pubprop($x, "conference", $docdatum); $this->pubprop($x, "proceedings", $docdatum); $this->pubprop($x, "journal", $docdatum); $this->pubprop($x, "isbn", $docdatum); $this->pubprop($x, "volume", $docdatum); $this->pubprop($x, "startPage", $docdatum); $this->pubprop($x, "endPage", $docdatum); $this->pubprop($x, "year", $docdatum); $this->pubprop($x, "publisher", $docdatum); $type = $this->el($x, "publication:type"); if (!is_null($type)) { $docdatum['typeID'] = strval($type->attributes()->id); } $intAuthors = array(); $extAuthors = array(); $authors = $x->xpath('publication:author[@type="internal"]'); foreach ($authors as $a) { if ($this->el($a, "person:person") === null) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; $this->_extError = "expected 'person:person' element under 'publication:author[@type=\"internal\"]' not found"; return $app; } else { $intAuthors[] = array(strval($this->el($a, "person:person")->attributes()->id), strval($a->attributes()->main)); } } $docdatum['intAuthors'] = $intAuthors; $authors = $x->xpath('publication:author[@type="external"]'); foreach ($authors as $a) { if ($this->el($a, "publication:extAuthor") === null) { $this->_error = RestErrorEnum::RE_INVALID_REPRESENTATION; $this->_extError = "expected 'publication:extAuthor' element under 'publication:author[@type=\"external\"]' not found"; return $app; } else { $extAuthors[] = array(strval($this->el($a, "publication:extAuthor")), strval($a->attributes()->main)); } } $docdatum['extAuthors'] = $extAuthors; $docdata[] = $docdatum; } } if (!is_null($docdata)) { $docs = new Default_Model_AppDocuments(); $docs->filter->appid->equals($app->id); $docs->refresh(); $docCount = count($docs->items); //handle existing and deleted entries for ($i = $docCount - 1; $i >= 0; $i--) { $existing = null; if (is_array($docdata)) { for ($j = 0; $j < count($docdata); $j++) { $doc = $docs->items[$i]; if ($doc->id == $docdata[$j]['id']) { $existing = $this->populateAppDoc($doc, $docdata[$j]); $docdata[$j]['PARSED'] = true; break; } } } if ($existing === null) { $docs->remove($docs->items[$i]); } else { $existing->save(); } } //handle new entries if (is_array($docdata)) { foreach ($docdata as $docdatum) { if (!isset($docdatum['PARSED']) || $docdatum['PARSED'] !== true) { $doc = new Default_Model_AppDocument(); //first time only main data is saved $doc->appID = $app->id; $doc = $this->populateAppDoc($doc, $docdatum); $docs->add($doc); //second time referenced data is saved $doc = $this->populateAppDoc($doc, $docdatum); $doc->save(); } } } } } if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { $xrels = $xml->xpath("application:relation"); $ps = new Default_Model_Applications(); $ps->filter->id->equals($app->id); $p = null; $res = true; if (count($ps->items) > 0) { $p = $ps->items[0]; } if ($p !== null) { $rels = array(); if (count($xml->xpath('application:relation[@xsi:nil="true"]')) === 0) { foreach ($xrels as $x) { $targuid = trim(strval($x->attributes()->targetguid)); $subguid = trim(strval($x->attributes()->subjectguid)); $rel = array("id" => trim(strval($x->attributes()->id)), "parentid" => trim(strval($x->attributes()->parentid))); if ($targuid === "") { $rel["subjectguid"] = $subguid; } else { if ($subguid === "") { $rel["targetguid"] = $targuid; } } if ($rel["parentid"] === "") { $rel["parentid"] = null; } $rels[] = $rel; } } try { $res = ApplicationRelations::syncRelations($p->guid, $this->_user->id, $rels); } catch (Exception $ex) { $res = $ex->getMessage(); error_log($res); } if (is_string($res)) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $res; return $p; } } } if ($this->_parent->getMethod() === RestMethodEnum::RM_POST) { $xrels = $xml->xpath("application:extrelation"); $ps = new Default_Model_Applications(); $ps->filter->id->equals($app->id); $p = null; if (count($ps->items) > 0) { $p = $ps->items[0]; } if ($p !== null && trim($app->metatype) !== "2") { $rels = array(); if (count($xml->xpath('application:extrelation[@xsi:nil="true"]')) === 0) { foreach ($xrels as $x) { $targuid = trim(strval($x->attributes()->targetguid)); $subguid = trim(strval($x->attributes()->subjectguid)); $rel = array("id" => trim(strval($x->attributes()->id)), "hidden" => trim(strval($x->attributes()->hidden))); $rels[] = $rel; } try { $res = ApplicationRelations::hideExternalRelations($p->guid, $this->_user->id, $rels); } catch (Exception $ex) { $res = $ex->getMessage(); error_log($res); } if (is_string($res)) { $this->_error = RestErrorEnum::RE_BACKEND_ERROR; $this->_extError = $res; return $p; } } } } } $this->_error = RestErrorEnum::RE_OK; return $app; }