Example #1
0
 /**
  * Logic for processing an $entry into a Mahara view.
  * @param SimpleXMLElement $entry
  * @return array An array of data that can be used to create the view, or store it into an import_request
  */
 private function get_mahara_view_entry_data(SimpleXMLElement $entry)
 {
     static $blocktypes_installed = null;
     static $columnlayouts = null;
     static $viewtypes = null;
     $viewelement = $entry->xpath('mahara:view[1]');
     if (count($viewelement) != 1) {
         // This isn't a Mahara view
         return false;
     }
     if (is_null($columnlayouts)) {
         $columnlayouts = get_records_assoc('view_layout_columns');
     }
     if (is_null($viewtypes)) {
         $viewtypes = get_column('view_type', 'type');
     }
     $maharaattributes = PluginImportLeap::get_attributes($viewelement[0], PluginImportLeap::NS_MAHARA);
     $type = 'portfolio';
     if (isset($maharaattributes['type']) && in_array($maharaattributes['type'], $viewtypes)) {
         $type = $maharaattributes['type'];
     }
     $ownerformat = intval($maharaattributes['ownerformat']);
     if (!$ownerformat) {
         $ownerformat = FORMAT_NAME_DISPLAYNAME;
     }
     $rows = $entry->xpath('mahara:view[1]/mahara:row');
     $rowcount = count($rows);
     // A flag that indicates whether this is an old-style one-row layout, or a new-style multi-row layout
     $onerowlayout = false;
     if ($rowcount < 1 || $rowcount > View::$maxlayoutrows) {
         // Check for a pre-1.8 (one-row) layout
         $columns = $entry->xpath('mahara:view[1]/mahara:column');
         $columncount = count($columns);
         if ($columncount < 1 || $columncount > 5) {
             // Whoops, invalid number of rows
             $this->trace("Invalid number of rows specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
             return false;
         } else {
             $onerowlayout = true;
             $rows = array($columns);
             $rowcount = 1;
         }
     }
     $layout = null;
     if (isset($maharaattributes['layout'])) {
         $rowwidths = explode('-', $maharaattributes['layout']);
         if (count($rowwidths) != $rowcount) {
             $this->trace("Row widths and number of rows do not match for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
             return false;
         }
         $columnids = array();
         foreach ($columnlayouts as $columnlayout) {
             foreach ($rowwidths as $key => $widths) {
                 if ($columnlayout->widths == $widths) {
                     $columnids[$key + 1] = $columnlayout->id;
                 }
             }
         }
         if (count($columnids) != $rowcount) {
             $this->trace("Invalid row widths were specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
             return false;
         }
         $rowscolssql = '';
         for ($i = 0; $i < count($columnids); $i++) {
             $rowscolssql .= '(row = ' . ($i + 1) . ' AND columns = ' . $columnids[$i + 1] . ')';
             if ($i != count($columnids) - 1) {
                 $rowscolssql .= ' OR ';
             }
         }
         // search in default layout options for a match
         // this will return first possible match with exact match (if any)
         // at front of possibles. More than one possible match can occur
         // if there are 3 or more rows in leap2a layout and 2 of those rows
         // match more than one possible view layout.
         $sql = 'SELECT vlrc.viewlayout AS id
                 FROM
                     {view_layout} vl
                     INNER JOIN {view_layout_rows_columns} vlrc
                         ON vl.id = vlrc.viewlayout
                     INNER JOIN (
                         SELECT
                             viewlayout, COUNT(*)
                         FROM {view_layout_rows_columns}
                         GROUP BY viewlayout
                         HAVING COUNT(*) = ?
                     ) vlrc2
                         ON vlrc.viewlayout = vlrc2.viewlayout
                     INNER JOIN {usr_custom_layout} ucl
                         ON ucl.layout = vl.id
                 WHERE (' . $rowscolssql . ')
                     AND (
                         vl.iscustom = 0
                         OR (
                             vl.iscustom = 1 AND ucl.usr = ? AND ucl.group IS NULL AND ucl.institution IS NULL
                         )
                     )
                 GROUP BY vlrc.viewlayout
                 HAVING count(*) = ?
                 LIMIT 1';
         $layout = get_record_sql($sql, array($rowcount, $this->get('usr'), $rowcount));
         if (!$layout) {
             require_once get_config('docroot') . 'lib/layoutpreviewimage.php';
             // No existing layout matches their page. This probably means they used a custom layout. So, create a new custom layout for them.
             // First check to see whether the custom layout they're using is acceptable in our system
             // TODO: A clever way to squeeze their page into one of the standard layouts if it isn't acceptable.
             // Maybe just put everything into a one-column layout and let them rearrange it?
             if (count($rowwidths) < 1 || count($rowwidths) > View::$maxlayoutrows) {
                 $this->trace("Invalid layout specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
                 return false;
             }
             $i = 1;
             $layoutdata = array();
             $layoutdata['numrows'] = count($rowwidths);
             foreach ($rowwidths as $row) {
                 // First, check to see whether this row matches a valid row layout in the DB
                 $rowcolid = get_field('view_layout_columns', 'id', 'widths', $row);
                 if (!$rowcolid) {
                     $this->trace("Invalid layout specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
                     return false;
                 }
                 // Data to help us generate the layout
                 $layoutdata["row{$i}"] = $rowcolid;
                 $i++;
             }
             // Now that we know the layout is valid, generate a record and a thumbnail image for it.
             db_begin();
             // An empty view object, since this view isn't present in the DB yet. We need this in order to access the layout methods
             $viewobj = new View(0, array('owner' => $this->get('usr'), 'deleted' => true));
             $layoutresult = $viewobj->addcustomlayout($layoutdata);
             if (empty($layoutresult['layoutid'])) {
                 $this->trace("Invalid layout specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
                 db_rollback();
                 return false;
             }
             $layout = (object) array('id' => $layoutresult['layoutid']);
             db_commit();
         }
     }
     // Extract the view description in the entry 'summary'
     // A description may be wrapped in XHTML div
     // See more PluginExportLeap::parse_xhtmlish_content()
     $description = '';
     if ((string) $entry->summary['type'] === 'xhtml' || (string) $entry->summary['type'] === 'html') {
         $summaryelements = (string) $entry->summary['type'] === 'xhtml' && $entry->summary->div->div ? $entry->summary->div->div : $entry->summary;
         $summarychildren = $summaryelements->children();
         foreach ($summarychildren as $c) {
             $description .= $c->asXML();
         }
     } else {
         $description = (string) $entry->summary;
     }
     $config = array('title' => (string) $entry->title, 'description' => $description, 'type' => $type, 'layout' => $layout->id, 'tags' => self::get_entry_tags($entry), 'numrows' => $rowcount, 'owner' => $this->get('usr'), 'ownerformat' => $ownerformat);
     $rowindex = 1;
     foreach ($rows as $row) {
         // If this is the old one-row layout, we'll have handled that earlier, and have the one row's columns be in $columns
         if (!$onerowlayout) {
             $columns = $row->xpath('mahara:column');
             $columncount = count($columns);
             if ($columncount < 1 || $columncount > 5) {
                 // Whoops, invalid number of columns
                 $this->trace("Invalid number of columns specified for potential view {$entry->id}, falling back to standard import", self::LOG_LEVEL_VERBOSE);
                 return false;
             }
         }
         $colindex = 1;
         foreach ($columns as $column) {
             $blockinstances = $column->xpath('mahara:blockinstance');
             $order = 1;
             $config['rows'][$rowindex]['columns'][$colindex] = array();
             foreach ($blockinstances as $blockinstance) {
                 $attrs = self::get_attributes($blockinstance, PluginImportLeap::NS_MAHARA);
                 if (!isset($attrs['blocktype'])) {
                     $this->trace("  No mahara:blocktype attribute set for blockinstance at row {$rowindex} col {$colindex}, order {$order}: skipping");
                     continue;
                 }
                 $this->trace("  Found block with type {$attrs['blocktype']} at [{$rowindex}][{$colindex}][{$order}]", self::LOG_LEVEL_VERBOSE);
                 if ($blocktypes_installed === null) {
                     $blocktypes_installed = array_map(create_function('$a', 'return $a->name;'), plugins_installed('blocktype'));
                 }
                 if (in_array($attrs['blocktype'], $blocktypes_installed)) {
                     $configelements = $blockinstance->xpath('mahara:*');
                     $config['rows'][$rowindex]['columns'][$colindex][$order] = array('type' => $attrs['blocktype'], 'title' => $attrs['blocktitle'], 'config' => array());
                     foreach ($configelements as $element) {
                         $value = json_decode((string) $element);
                         if (is_array($value) && isset($value[0])) {
                             $config['rows'][$rowindex]['columns'][$colindex][$order]['config'][$element->getName()] = $value[0];
                         } else {
                             $this->trace("  Value for {$element->getName()} is not an array, ignoring (value follows below)");
                             $this->trace($value);
                         }
                     }
                     $order++;
                 } else {
                     $this->trace("  Ignoring unknown blocktype {$attrs['blocktype']}");
                 }
             }
             $colindex++;
         }
         // cols
         $rowindex++;
     }
     //rows
     return $config;
 }