/** * Get the id of the plan entry which ultimately contains this entry */ public static function get_ancestor_entryid(SimpleXMLElement $entry, PluginImportLeap $importer) { $entryid = (string) $entry->id; if (!isset(self::$ancestors[$entryid])) { self::$ancestors[$entryid] = null; $child = $entry; while ($child) { $childid = (string) $child->id; if (!isset(self::$parents[$childid])) { self::$parents[$childid] = null; foreach ($child->link as $link) { $href = (string) $link['href']; if ($href != $entryid && $importer->curie_equals($link['rel'], PluginImportLeap::NS_LEAP, 'is_part_of') && $importer->entry_has_strategy($href, self::STRATEGY_IMPORT_AS_PLAN, 'plans')) { self::$parents[$childid] = $href; break; } } } if (!self::$parents[$childid]) { break; } if ($child = $importer->get_entry_by_id(self::$parents[$childid])) { self::$ancestors[$entryid] = self::$parents[$childid]; } } } return self::$ancestors[$entryid]; }
/** * Given an entry, see if it's attached to one of the special selections * representing a Mahara resume group. If so, return the display order it * should have in that group. * * We look for the special Mahara selections only, because entries could be * in more than one selection, with different display orders in each. * * @param SimpleXMLElement $entry The entry to check * @param PluginImportLeap $importer The importer * @param string $selectiontype The type of selection we're checking to * see if the entry is part of - one of the * special Mahara resume selections * @return int The display order of the element in the selection, should it * be in one - else null */ private static function get_display_order_for_entry(SimpleXMLElement $entry, PluginImportLeap $importer, $selectiontype) { static $cache = array(); $found = false; foreach ($entry->link as $link) { if ($importer->curie_equals($link['rel'], $importer->get_leap2a_namespace(), 'is_part_of') && isset($link['href'])) { $href = (string) $link['href']; if (isset($cache[$href])) { $found = true; } else { if ($potentialselection = $importer->get_entry_by_id($href)) { if (PluginImportLeap::is_rdf_type($potentialselection, $importer, 'selection')) { if (PluginImportLeap::is_correct_category_scheme($potentialselection, $importer, 'selection_type', 'Grouping')) { if (count($potentialselection->xpath('mahara:artefactplugin[@mahara:type="' . $selectiontype . '"]')) == 1) { $cache[$href] = true; $found = true; } } } } } if ($found) { $leapattributes = $importer->get_attributes($link, $importer->get_leap2a_namespace()); $displayorder = isset($leapattributes['display_order']) && intval($leapattributes['display_order']) > 0 ? $leapattributes['display_order'] : ''; return $displayorder; } } } }
/** * Import data about the feed author. * * If we have a persondata element for them, we can import lots of * different information about them into Mahara's profile section. * Otherwise, we can only import some very basic information from the * <author> element. * * TODO: Refactor this to combine it with add_import_entry_request_author_data() * * @param PluginImportLeap $importer The importer * @param string $persondataid The ID of the person entry corresponding * to the author, if there is one */ public static function import_author_data(PluginImportLeap $importer, $persondataid) { $namespaces = $importer->get_namespaces(); $ns = $namespaces[$importer->get_leap2a_namespace()]; if ($persondataid) { // Grab all the leap:persondata elements and import them $person = $importer->get_entry_by_id($persondataid); // The introduction comes from the entry content if (!self::$personcontentblank) { $introduction = new ArtefactTypeIntroduction(0, array('owner' => $importer->get('usr'))); $introduction->set('title', PluginImportLeap::get_entry_content($person, $importer)); $introduction->commit(); } // Most of the rest of the profile data comes from leap:persondata elements $persondata = $person->xpath($ns . ':persondata'); foreach ($persondata as $item) { $leapattributes = PluginImportLeap::get_attributes($item, $importer->get_leap2a_namespace()); if (isset($leapattributes['field'])) { self::import_persondata($importer, $item, $leapattributes); } else { // 'Field' is required // http://wiki.cetis.ac.uk/2009-03/Leap2A_personal_data#field $importer->trace('WARNING: persondata element did not have leap:field attribute'); continue; } } // The information about someone's name is much more comprehensive // in Leap than what Mahara has, so we have to piece it together self::import_namedata($importer, $persondata); // People can have address info associated with them $addressdata = $person->xpath($ns . ':spatial'); if (is_array($addressdata) && count($addressdata) == 1) { self::import_addressdata($importer, $addressdata[0]); } // Set default profile icon. We look at rel="related" links on this // element, and take the first one that we turned into a profile // icon to be the default. In future versions of the spec, we may use // a "depicts" type relationship to explicitly identify them. foreach ($person->link as $link) { if ($importer->curie_equals($link['rel'], '', 'related') && isset($link['href'])) { $artefactids = $importer->get_artefactids_imported_by_entryid((string) $link['href']); if (count($artefactids) == 1 && ($potentialicon = artefact_instance_from_id($artefactids[0]))) { if ($potentialicon->get('artefacttype') == 'profileicon') { $importer->get('usrobj')->profileicon = $potentialicon->get('id'); $importer->get('usrobj')->commit(); // The first one we find in the export is the profile icon break; } } } } } else { $author = $importer->get('xml')->xpath('//a:feed/a:author[1]'); $author = $author[0]; if (!isset($author->name)) { throw new ImportException($importer, 'TODO: get_string: <author> must include <name> - http://wiki.cetis.ac.uk/2009-03/Leap2A_relationships#Author'); } $name = (string) $author->name; if (false !== strpos($name, ' ')) { list($firstname, $lastname) = explode(' ', $name, 2); self::create_artefact($importer, 'firstname', trim($firstname)); self::create_artefact($importer, 'lastname', trim($lastname)); } else { // Blatant assumtion that the <name> is a first name self::create_artefact($importer, 'firstname', trim($name)); } if (isset($author->email)) { self::create_artefact($importer, 'email', (string) $author->email); } if (isset($author->uri)) { $uri = (string) $author->uri; if (preg_match('#^https?://#', $uri)) { self::create_artefact($importer, 'officialwebsite', (string) $author->uri); } } } }
/** * Fix comments to point to the right view. Probably more * appropriate in setup_relationships. To do that we would have * to change that call to happen after views are created. */ public static function setup_view_relationships_from_request(PluginImportLeap $importer) { if ($entry_requests = get_records_select_array('import_entry_requests', 'importid = ? AND entrytype = ?', array($importer->get('importertransport')->get('importid'), 'comment'))) { foreach ($entry_requests as $entry_request) { $commentids = unserialize($entry_request->artefactmapping); $comment = new ArtefactTypeComment($commentids[0]); if ($comment->get('onartefact')) { continue; } $entry = $importer->get_entry_by_id($entry_request->entryid); $referentid = self::get_referent_entryid($entry, $importer); if ($viewid = $importer->get_viewid_imported_by_entryid($referentid)) { $comment->set('onview', $viewid); $comment->commit(); } else { // Nothing to link this comment to, so leave it in the temporary view. self::$savetempview = true; } } } }
/** * Returns a list of entry IDs that are children of this folder * * If necessary, this method can act recursively to find children at all * levels under this folder * * TODO: protection against circular references * * @param SimpleXMLElement $entry The folder to get children for * @param PluginImportLeap $importer The importer * @param boolean $recurse Whether to return children at all levels below this folder * @return array A list of the entry IDs of children in this folder */ private static function get_children_of_folder(SimpleXMLElement $entry, PluginImportLeap $importer, $recurse = false) { $children = array(); // Get entries that this folder feels are a part of it foreach ($entry->link as $link) { if ($importer->curie_equals($link['rel'], $importer->get_leap2a_namespace(), 'has_part') && isset($link['href'])) { $child = $importer->get_entry_by_id((string) $link['href']); if ($child) { if (self::is_file($child, $importer) || self::is_folder($child, $importer)) { $children[] = (string) $link['href']; } else { $importer->trace("NOTICE: Child {$child->id} of folder {$entry->id} won't be imported by the file plugin because it is not a file or folder"); } } else { $importer->trace("WARNING: folder {$entry->id} claims to have child {$link['href']} which does not exist"); } } } if ($recurse) { foreach ($children as $childid) { $child = $importer->get_entry_by_id($childid); if (self::is_folder($child, $importer)) { $children = array_merge($children, self::get_children_of_folder($child, $importer, true)); } } } return $children; }
/** * Fix annotations to point to the right view. */ public static function setup_view_relationships_from_requests(PluginImportLeap $importer) { // Get all the annotations imported. if ($entry_requests = get_records_select_array('import_entry_requests', 'importid = ? AND entrytype = ?', array($importer->get('importertransport')->get('importid'), 'annotation'))) { foreach ($entry_requests as $entry_request) { $annotationids = $importer->get_artefactids_imported_by_entryid($entry_request->entryid); $annotation = new ArtefactTypeAnnotation($annotationids[0]); if (!$annotation->get('id')) { continue; } $annotation_entry = $importer->get_entry_by_id($entry_request->entryid); $view_entry_request = self::get_referent_entryid($annotation_entry, $importer); // Now see which view had this entryid. if ($viewid = $importer->get_viewid_imported_by_entryid($view_entry_request)) { // Set the view on the annotation. $annotation->set('view', $viewid); $annotation->commit(); } else { // Nothing to link this annotation to, so leave it in the temporary view. self::$savetempview = true; } } } }
/** * Attaches files to blog posts * * We look at the leap relationships to add attachments. Currently this * looks explicitly for the has_attachment relationship. * * If importing an entry resulted in importing a new file (caused by the * entry having out-of-line content), we attach that file to the entry. */ public static function setup_relationships(SimpleXMLElement $entry, PluginImportLeap $importer, $strategy, array $otherentries) { $newartefactmapping = array(); switch ($strategy) { case self::STRATEGY_IMPORT_AS_BLOG: foreach ($otherentries as $entryid) { $blogpostentry = $importer->get_entry_by_id($entryid); // Get all attachments this blogpost things are attached to it if (!isset($blogpostentry->link)) { continue; } $blogpost = null; foreach ($blogpostentry->link as $blogpostlink) { if (!$blogpost) { $artefactids = $importer->get_artefactids_imported_by_entryid((string) $blogpostentry->id); $blogpost = new ArtefactTypeBlogPost($artefactids[0]); } if ($id = $importer->create_attachment($entry, $blogpostlink, $blogpost)) { $newartefactmapping[$link['href']][] = $id; } if ($blogpost) { $blogpost->commit(); } } self::setup_outoflinecontent_relationship($blogpostentry, $importer); } break; case self::STRATEGY_IMPORT_AS_ENTRY: $blogpostids = $importer->get_artefactids_imported_by_entryid((string) $entry->id); if (!isset($blogpostids[0])) { // weird! break; } $blogpost = new ArtefactTypeBlogPost($blogpostids[0]); foreach ($entry->link as $link) { if ($id = $importer->create_attachment($entry, $link, $blogpost)) { $newartefactmapping[$link['href']][] = $id; } } $blogpost->commit(); self::setup_outoflinecontent_relationship($entry, $importer); break; default: throw new ImportException($importer, 'TODO: get_string: unknown strategy chosen for importing entry'); } return $newartefactmapping; }