MDL-50015 mod_imscp: New WS mod_imscp_view_imscp
[moodle.git] / mod / book / tool / exportimscp / locallib.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * Book imscp export lib
19  *
20  * @package    booktool_exportimscp
21  * @copyright  2001-3001 Antonio Vicent          {@link http://ludens.es}
22  * @copyright  2001-3001 Eloy Lafuente (stronk7) {@link http://stronk7.com}
23  * @copyright  2011 Petr Skoda                   {@link http://skodak.org}
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25  */
27 defined('MOODLE_INTERNAL') || die;
29 require_once(dirname(__FILE__).'/lib.php');
30 require_once($CFG->dirroot.'/mod/book/locallib.php');
32 /**
33  * Export one book as IMSCP package
34  *
35  * @param stdClass $book book instance
36  * @param context_module $context
37  * @return bool|stored_file
38  */
39 function booktool_exportimscp_build_package($book, $context) {
40     global $DB;
42     $fs = get_file_storage();
44     if ($packagefile = $fs->get_file($context->id, 'booktool_exportimscp', 'package', $book->revision, '/', 'imscp.zip')) {
45         return $packagefile;
46     }
48     // fix structure and test if chapters present
49     if (!book_preload_chapters($book)) {
50         print_error('nochapters', 'booktool_exportimscp');
51     }
53     // prepare temp area with package contents
54     booktool_exportimscp_prepare_files($book, $context);
56     $packer = get_file_packer('application/zip');
57     $areafiles = $fs->get_area_files($context->id, 'booktool_exportimscp', 'temp', $book->revision, "sortorder, itemid, filepath, filename", false);
58     $files = array();
59     foreach ($areafiles as $file) {
60         $path = $file->get_filepath().$file->get_filename();
61         $path = ltrim($path, '/');
62         $files[$path] = $file;
63     }
64     unset($areafiles);
65     $packagefile = $packer->archive_to_storage($files, $context->id, 'booktool_exportimscp', 'package', $book->revision, '/', 'imscp.zip');
67     // drop temp area
68     $fs->delete_area_files($context->id, 'booktool_exportimscp', 'temp', $book->revision);
70     // delete older versions
71     $sql = "SELECT DISTINCT itemid
72               FROM {files}
73              WHERE contextid = :contextid AND component = 'booktool_exportimscp' AND itemid < :revision";
74     $params = array('contextid'=>$context->id, 'revision'=>$book->revision);
75     $revisions = $DB->get_records_sql($sql, $params);
76     foreach ($revisions as $rev => $unused) {
77         $fs->delete_area_files($context->id, 'booktool_exportimscp', 'temp', $rev);
78         $fs->delete_area_files($context->id, 'booktool_exportimscp', 'package', $rev);
79     }
81     return $packagefile;
82 }
84 /**
85  * Prepare temp area with the files used by book html contents
86  *
87  * @param stdClass $book book instance
88  * @param context_module $context
89  */
90 function booktool_exportimscp_prepare_files($book, $context) {
91     global $CFG, $DB;
93     $fs = get_file_storage();
95     $temp_file_record = array('contextid'=>$context->id, 'component'=>'booktool_exportimscp', 'filearea'=>'temp', 'itemid'=>$book->revision);
96     $chapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum');
97     $chapterresources = array();
98     foreach ($chapters as $chapter) {
99         $chapterresources[$chapter->id] = array();
100         $files = $fs->get_area_files($context->id, 'mod_book', 'chapter', $chapter->id, "sortorder, itemid, filepath, filename", false);
101         foreach ($files as $file) {
102             $temp_file_record['filepath'] = '/'.$chapter->pagenum.$file->get_filepath();
103             $fs->create_file_from_storedfile($temp_file_record, $file);
104             $chapterresources[$chapter->id][] = $chapter->pagenum.$file->get_filepath().$file->get_filename();
105         }
106         if ($file = $fs->get_file($context->id, 'booktool_exportimscp', 'temp', $book->revision, "/$chapter->pagenum/", 'index.html')) {
107             // this should not exist
108             $file->delete();
109         }
110         $content = booktool_exportimscp_chapter_content($chapter, $context);
111         $index_file_record = array('contextid'=>$context->id, 'component'=>'booktool_exportimscp', 'filearea'=>'temp',
112                 'itemid'=>$book->revision, 'filepath'=>"/$chapter->pagenum/", 'filename'=>'index.html');
113         $fs->create_file_from_string($index_file_record, $content);
114     }
116     $css_file_record = array('contextid'=>$context->id, 'component'=>'booktool_exportimscp', 'filearea'=>'temp',
117             'itemid'=>$book->revision, 'filepath'=>"/css/", 'filename'=>'styles.css');
118     $fs->create_file_from_pathname($css_file_record, dirname(__FILE__).'/imscp.css');
120     // Init imsmanifest and others
121     $imsmanifest = '';
122     $imsitems = '';
123     $imsresources = '';
125     // Moodle and Book version
126     $moodle_release = $CFG->release;
127     $moodle_version = $CFG->version;
128     $book_version   = get_config('mod_book', 'version');
129     $bookname       = format_string($book->name, true, array('context'=>$context));
131     // Load manifest header
132         $imsmanifest .= '<?xml version="1.0" encoding="UTF-8"?>
133 <!-- This package has been created with Moodle ' . $moodle_release . ' (' . $moodle_version . ') http://moodle.org/, Book module version ' . $book_version . ' - https://github.com/skodak/moodle-mod_book -->
134 <!-- One idea and implementation by Eloy Lafuente (stronk7) and Antonio Vicent (C) 2001-3001 -->
135 <manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1" xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" identifier="MANIFEST-' . md5($CFG->wwwroot . '-' . $book->course . '-' . $book->id) . '" xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1 imscp_v1p1.xsd http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">
136   <organizations default="MOODLE-' . $book->course . '-' . $book->id . '">
137     <organization identifier="MOODLE-' . $book->course . '-' . $book->id . '" structure="hierarchical">
138       <title>' . htmlspecialchars($bookname) . '</title>';
140     // To store the prev level (book only have 0 and 1)
141     $prevlevel = null;
142     $currlevel = 0;
143     foreach ($chapters as $chapter) {
144         // Calculate current level ((book only have 0 and 1)
145         $currlevel = empty($chapter->subchapter) ? 0 : 1;
146         // Based upon prevlevel and current one, decide what to close
147         if ($prevlevel !== null) {
148             // Calculate the number of spaces (for visual xml-text formating)
149             $prevspaces = substr('                ', 0, $currlevel * 2);
151             // Same level, simply close the item
152             if ($prevlevel == $currlevel) {
153                 $imsitems .= $prevspaces . '        </item>' . "\n";
154             }
155             // Bigger currlevel, nothing to close
156             // Smaller currlevel, close both the current item and the parent one
157             if ($prevlevel > $currlevel) {
158                 $imsitems .= '          </item>' . "\n";
159                 $imsitems .= '        </item>' . "\n";
160             }
161         }
162         // Update prevlevel
163         $prevlevel = $currlevel;
165         // Calculate the number of spaces (for visual xml-text formatting)
166         $currspaces = substr('                ', 0, $currlevel * 2);
168         $chaptertitle = format_string($chapter->title, true, array('context'=>$context));
170         // Add the imsitems
171         $imsitems .= $currspaces .'        <item identifier="ITEM-' . $book->course . '-' . $book->id . '-' . $chapter->pagenum .'" isvisible="true" identifierref="RES-' .
172                 $book->course . '-' . $book->id . '-' . $chapter->pagenum . "\">\n" .
173                 $currspaces . '         <title>' . htmlspecialchars($chaptertitle) . '</title>' . "\n";
175         // Add the imsresources
176         // First, check if we have localfiles
177         $localfiles = array();
178         foreach ($chapterresources[$chapter->id] as $localfile) {
179             $localfiles[] = "\n" . '      <file href="' . $localfile . '" />';
180         }
181         // Now add the dependency to css
182         $cssdependency = "\n" . '      <dependency identifierref="RES-' . $book->course . '-'  . $book->id . '-css" />';
183         // Now build the resources section
184         $imsresources .= '    <resource identifier="RES-' . $book->course . '-'  . $book->id . '-' . $chapter->pagenum . '" type="webcontent" xml:base="' .
185                 $chapter->pagenum . '/" href="index.html">' . "\n" .
186                 '      <file href="' . $chapter->pagenum . '/index.html" />' . implode($localfiles) . $cssdependency . "\n".
187                 '    </resource>' . "\n";
188     }
190     // Close items (the latest chapter)
191     // Level 1, close 1
192     if ($currlevel == 0) {
193         $imsitems .= '        </item>' . "\n";
194     }
195     // Level 2, close 2
196     if ($currlevel == 1) {
197         $imsitems .= '          </item>' . "\n";
198         $imsitems .= '        </item>' . "\n";
199     }
201     // Define the css common resource
202     $cssresource = '    <resource identifier="RES-' . $book->course . '-'  . $book->id . '-css" type="webcontent" xml:base="css/" href="styles.css">
203       <file href="css/styles.css" />
204     </resource>' . "\n";
206     // Add imsitems to manifest
207     $imsmanifest .= "\n" . $imsitems;
208     // Close the organization
209     $imsmanifest .= "    </organization>
210   </organizations>";
211     // Add resources to manifest
212     $imsmanifest .= "\n  <resources>\n" . $imsresources . $cssresource . "  </resources>";
213     // Close manifest
214     $imsmanifest .= "\n</manifest>\n";
216     $manifest_file_record = array('contextid'=>$context->id, 'component'=>'booktool_exportimscp', 'filearea'=>'temp',
217             'itemid'=>$book->revision, 'filepath'=>"/", 'filename'=>'imsmanifest.xml');
218     $fs->create_file_from_string($manifest_file_record, $imsmanifest);
221 /**
222  * Returns the html contents of one book's chapter to be exported as IMSCP
223  *
224  * @param stdClass $chapter the chapter to be exported
225  * @param context_module $context context the chapter belongs to
226  * @return string the contents of the chapter
227  */
228 function booktool_exportimscp_chapter_content($chapter, $context) {
230     $options = new stdClass();
231     $options->noclean = true;
232     $options->context = $context;
234     $chaptercontent = str_replace('@@PLUGINFILE@@/', '', $chapter->content);
235     $chaptercontent = format_text($chaptercontent, $chapter->contentformat, $options);
237     $chaptertitle = format_string($chapter->title, true, array('context'=>$context));
239     $content = '';
240     $content .= '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">' . "\n";
241     $content .= '<html>' . "\n";
242     $content .= '<head>' . "\n";
243     $content .= '<meta http-equiv="content-type" content="text/html; charset=utf-8" />' . "\n";
244     $content .= '<link rel="stylesheet" type="text/css" href="../css/styles.css" />' . "\n";
245     $content .= '<title>' . $chaptertitle . '</title>' . "\n";
246     $content .= '</head>' . "\n";
247     $content .= '<body>' . "\n";
248     $content .= '<h1 id="header">' . $chaptertitle . '</h1>' ."\n";
249     $content .= $chaptercontent . "\n";
250     $content .= '</body>' . "\n";
251     $content .= '</html>' . "\n";
253     return $content;